• 课程资料


    一、登录页

    课程目标

    1. 复习vue脚手架
    2. 搭建vue大型项目框架
    3. 制作一级路由页面登录页面

    知识点

    1.v-model

    登录页有两个输入框,分别是用户名和密码。用户在输入框里输入的内容可以通过v-model指令和data进行双向数据绑定。
    可以带着学生回忆一下在没有vue的时候怎么做这个功能。在react里没有v-model指令,是通过受控组件来做的,两者有什么
    区别?能否在vue里用受控组件代替v-model?

    语法格式:

    <input v-model="username">
    

    2.axios

    前后端通信的工具,如何安装axios?添加登录按钮,并绑定登录事件,在登录回调函数里如何获取输入框里的值?
    获取到值后,使用axios把用户名和密码发送给后端。

    语法格式:

    <button @click="handleLogin">登录</button>
    
    methods: {
      handleLogin() {
        Api.login({ username: this.username, password: this.password }).then(res => {
        })
      }
    }
    

    3.如何写后端接口

    可以在vue.config.js里写,也可以利用在专高一时所学的知识,搭建后端项目,使用express写接口。
    vue.config.js是vue脚手架的api,会随着项目的启动自动加载。建议安装body-parser解析post请求。

    语法格式:

    const bodyParser = require('body-parser')
    
    let userList = [
      {
        id: 0,
        username: 'admin',
        password: '123456'
      },
      {
        id: 1,
        username: 'xu',
        password: '123'
      }
    ]
    
    module.exports = {
      lintOnSave: false,
      devServer: {
        open: true,
        before(app) {
    
          app.use(bodyParser.json())
    
          app.post('/api/login', (req, res) => {
            let { username, password } = req.body
            let user = userList.find(item => item.username === username)
            if (user) {
              if (user.password === password) {
                res.send({
                  code: 200,
                  data: {
                    username
                  },
                  message: '登录成功'
                })
              } else {
                res.send({
                  code: 400,
                  message: '密码错误'
                })
              }
            } else {
              res.send({
                code: 400,
                message: '用户名不存在'
              })
            }
          })
        }
      }
    }
    

    4.登录页面的优化

    首页要做的是用户名输入框自动获取焦点,可以给学生看看百度首页,每次刷新时百度首页的搜索框都会自动获取焦点,这样
    做对用户来说使用起来很方便!
    语法格式:

    <input v-model="username" placeholder="请输入用户名" autofocus >
    

    还有一个需要优化的是回车登录。这个也可以举百度的例子,就是用户输入完成后,点击回车键即可搜索!
    在vue里可以使用.enter修饰keyup事件做到这个功能。

    语法格式:

    <input @keyup.enter="handleLogin" >
    

    授课思路

    在这里插入图片描述

    案例作业

    1.练习v-model
    2.制作登录页
    3.前后端通信
    4.可以包含多个用户
    5.区分用户名错误和密码错误

    在这里插入图片描述

    二、登录页控制密码显示隐藏

    课程目标

    1. 复习登录页主要知识点
    2. 复习vue组件化的思想
    3. 讲解父子组件传值
    4. 讲解iconfont的用法以及为什么要用iconfont
    5. 封装Icon组件,使用iconfont,控制密码输入框的密码显示和隐藏

    知识点

    1.组件化思想

    组件化就是把传统的一张大网页拆分成很多小组件,有些组件可以反复使用,有些组件也许只使用一次,拆分成很多组件的目的就是使页面解构更清晰更好维护,也方便多人协作开发一个大项目。

    2.vue组件

    首先带学生回忆一下react里如何创建组件,然后再用快捷方式创建一个vue的组件。讲解vue组件的模板、js以及样式这三大模块在react组件里是如何实现的,还可以讲解一下jsx多么的方便,而vue又哪些弊端。再给学生展示一下vue和react在github上star数对比以及npm下载量对比。

    3.iconfont

    讲解iconfont和雪碧图的区别。现场演示登录iconfont网站,并添加眼睛睁开和眼睛闭上的图标,并下载到本地。打开demo页,调试网页,
    介绍iconfont的原理。

    4.制作Icon组件

    引入iconfont文件,编写Icon组件。
    重点内容:props的类型检查,如何动态绑定class,子组件触发父组件的方法

    语法格式:

    <template>
      <span :class="[ `icon iconfont icon-${name}` ]" @click="handleClick"></span>
    </template>
    
    <script>
    export default {
     props: {
       name: String
     },
     methods: {
       handleClick() {
         this.$emit('onClick')
       }
     }
    }
    </script>
    

    5.在登录页使用Icon组件

    如果引入组件并使用

    语法格式:

    <template>
      <div>
        <div>
          <input v-model="username" placeholder="请输入用户名" autofocus >
        </div>
        <div>
          <input v-model="password" placeholder="请输入密码" :type=" visible ? 'text' : 'password'" @keyup.enter="handleLogin" >
          <Icon :name="visible ? 'xianshimima' : 'buxianshimima'" class="m-login-icon" @onClick="handleVisible" ></Icon>
        </div>
        <button @click="handleLogin">登录</button>
      </div>
    </template>
    
    <script>
    import axios from 'axios'
    import Icon from '../components/Icon'
    import Api from '../api'
    
    export default {
      data() {
        return {
          username: 'admin',
          password: '123456',
          visible: false
        }
      },
      components: {
        Icon
      },
      methods: {
        handleLogin() {
          Api.login({ username: this.username, password: this.password }).then(res => {
            if (res.code === 200) {
              localStorage.setItem('token', res.data.username)
              this.$router.push('/index/home')
            } else {
              this.$message({ message: res.message, duration: 1000 })
            }
          })
        },
        handleVisible() {
          this.visible = !this.visible
        }
      }
    }
    </script>
    
    <style>
    
    </style>
    

    授课思路

    在这里插入图片描述

    案例作业

    1.完善登录页
    2.研究iconfont的用法
    3.编写vue组件
    4.控制密码的显示和隐藏

    在这里插入图片描述

    三、封装Api

    课程目标

    1. 讲解为什么要封装Api
    2. 首先封装url
    3. 其次要复习复习Promise
    4. 讲解拦截器
    5. 讲解封装本身代码

    知识点

    1.为啥要封装Api呢

    为了好维护,减少代码量!把前后端通信的url单独写的一个文件里,有多少接口就一目了然了。把所有前端发起请求的方法也写到一个文件里,方法名抛出,可以减少代码量。另外还可以给axios添加拦截器,对报错信息统一处理,统一添加请求头等等。

    2.首先封装url

    封装url并没有用到啥新技术,js模块化而已!把url归归类,也可以写写注释,甚至还可以继续拆分成多个文件,多人协同维护。

    语法格式:

    const urls = {
      login: '/api/login',
      list: '/api/list',
      myBooks: '/api/my_books'
    }
    
    export default urls
    

    3.复习Promise

    axios请求本身就是一个promise,如果想对axios进行二次封装,要好好研究一下。promise对象是可以通过.then处理成功的回调的,在封装之前大家一直也都这么用,封装之后也需要继续保持。async函数本身也是一个promise,且async函数内部可以通过await等待异步函数执行。

    4.拦截器

    拦截器只是一个概念,其实很好理解。可以类比之前讲的express中间件,其实二者的语法格式都是一致的。重点不是语法,重点是拦截器能帮咱干啥。可以类比高速公路的上高速前领一张卡和下高速前把卡交回并缴费。回到拦截器里就是请求前可以在header里添加token等信息,请求后可以帮忙这一些消息框的提示拦截。

    5.封装axios

    这块是核心代码,会有点多,核心思想就是把请求的核心部分封装成一个函数,抛出多个函数对应多个接口。

    语法格式:

    import axios from 'axios'
    import message from '../components/message'
    import urls from './urls'
    
    if (process.env.NODE_ENV === 'development') {
      axios.defaults.baseURL = 'http://localhost:81'
    }
    
    axios.interceptors.request.use((config) => {
      config.headers.token = localStorage.getItem('token')
      return config
    })
    
    axios.interceptors.response.use((res) => {
      if (res.data.code === 400) {
        message({ message: res.data.message, duration: 2000 })
      }
      return res
    })
    
    const common = async (config) => {
      let resolve = await axios(config)
      return resolve.data
    }
    
    const Api = {
      login: (data) => common({ url: urls.login, data, method: 'post' }),
      list: () => common({ url: urls.list }),
      myBooks: (data, method) => common({ url: urls.myBooks, data, method })
    }
    
    export default Api
    

    授课思路

    在这里插入图片描述

    案例作业

    1.登录页调用封装后的api
    2.在后端添加对一个数组的增删查改的接口
    3.前端封装对应的接口并调用
    4.研究get请求和post请求的区别

    四、二级路由

    课程目标

    1. 登录后跳转到新页面
    2. 新页面是个三段式
    3. header、footer拆分成组件
    4. 中间部分是二级路由,动态切换

    知识点

    1.如何跳转路由

    如果用户名和密码都是正确的,后端会返回登录成功,前端就需要跳转页面了。可以给学生扩展一下路由的原理,history模式和hash模式到底啥区别?

    语法格式:

      this.$router.push('/index/home')
    

    2.三段式

    盒子需要覆盖整个浏览器,flex纵向布局。头和尾高度固定,中间部分flex:1

    .m-wrap{display: flex;flex-direction: column;position: absolute;top: 0;left: 0;right: 0;bottom: 0;}
    .m-header{height: 40px;line-height: 40px;background: red;color: #fff;text-align: center;}
    .m-main{flex: 1;overflow-y: auto;}
    .m-footer{display: flex; height: 40px;box-shadow: 0 -5px 5px rgba(0,0,0,0.1);border-top: 1px solid #ddd; text-align: center;z-index: 9;}
    

    3.拆分组件

    组件化依然是主体,header和footer两个组件。这个两个组件还是有很多文章可以做的,可以简单讲一下先不展开,先把二级路由讲清楚!

    <template>
      <div class="m-wrap">
        <Header></Header>
        <router-view></router-view>
        <Footer></Footer>
      </div>
    </template>
    

    4.二级路由

    所谓二级,就是普通的页面里包含小页面。其实多少级都是一样的,学会二级就都学会了。router-view是页面渲染的地方,是可以嵌套。路由配置是数组对象,也可以通过children字段进行嵌套,和router-view形成对应。

    语法格式:

    const routes = [
      {
        path: '/index',
        component: Index,
        children: [{
          path: '/index/home',
          component: () => import('../views/Home')
        }]
      }
    ]
    
    

    授课思路

    在这里插入图片描述

    案例作业

    1.登录成功后跳转新页面
    2.新页面是三段式,头和尾是组件,中间是二级路由
    3.研究路由懒加载
    4.预习vuex

    五、引入VueX

    课程目标

    1. 通过案例引入VueX
    2. 让学生掌握VueX的基本语法
    3. 了解路由守卫

    知识点

    1.VueX

    VueX是难点、重点。可以多举一些有趣的例子加深学生理解。仓库好比是杂货铺,又好比是手机里的应用商店等等。还可以带着学生安装一下VueX在chrome里的插件,这样学习起来更直观些。这里把Vuex的最精简、最易上手的语法展示一下,学会这些就足够了,不必全面学习官方Api。

    语法格式:

    import Vue from 'vue'
    import Vuex from 'vuex'
    import Api from '../api'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        title: '小米书城'
      },
      mutations: {
        setState(state, payload) {
          state[payload.key] = payload.value
        }
      },
      actions: {
        getList({ commit }) {
          Api.list().then(res => {
            if (res.code === 200) {
              commit({ type: 'setState', key: 'list', value: res.data })
            }
          })
        }
      }
    })
    
    

    title是仓库里的值,mutations里的setState方法负责修改仓库里的值,actions只是一个写异步函数的地方。

    2.在Header里获取仓库里的值

    通过计算属性获取,语法很简单,获取之后的使用也和data里的数据完全一样。当然也可以使用辅助函数获取,不过我不喜欢使用。

    <template>
      <div class="m-header">
        {{title}}
      </div>
    </template>
    
    <script>
    export default {
      computed: {
        title() {
          return this.$store.state.title
        }
      }
    }
    </script>
    

    3.完善Footer组件

    Footer组件包含首页、书包和我的三个菜单,除了文字外,应该添加上小图标,这样会更加有趣!之前的课程中已经封装了Icon组件在密码输入框里使用,这里是第二次是否Icon组件,Icon组件还会再接下来的课程中继续使用。

    <template>
      <div class="m-footer">
        <router-link to="/index/home" class="m-footer-item">
          <Icon name="shouye" class="m-footer-icon"></Icon>
          <div class="m-footer-text">首页</div>
        </router-link>
        <router-link to="/index/my_books" class="m-footer-item">
          <Icon name="shubao" class="m-footer-icon"></Icon>
          <div class="m-footer-text">书包</div>
        </router-link>
        <router-link to="/index/me" class="m-footer-item">
          <Icon name="wodedangxuan" class="m-footer-icon"></Icon>
          <div class="m-footer-text">我的</div>
        </router-link>
      </div>
    </template>
    

    4.点击底部菜单动态修改Header里的文本

    如果直接在底部菜单上面绑定click事件,点击的时候修改仓库里的title值,确实可以实现这个需求,但是刷新后会出bug,你可以试一试!原因很简单,store里的数据刷新后就回到初始值了。这里推荐一个新的解决方案,通过路由守卫实现!

    语法格式:

      children: [{
        path: '/index/home',
        component: () => import('../views/Home'),
        meta: {
          title: '小米书城'
        }
      }, {
        path: '/index/my_books',
        component: () => import('../views/MyBooks'),
        meta: {
          title: '我的书包'
        }
      }, {
        path: '/index/me',
        component: () => import('../views/Me'),
        meta: {
          title: '个人中心'
        }
      }]
    
    router.beforeEach((to, from, next) => {
      store.commit({ type: 'setState', key: 'title', value: to.meta.title })
      next()
    })
    
    

    授课思路

    在这里插入图片描述

    案例作业

    1.学习VueX语法
    2.实现底部菜单切换顶部Header文本
    3.学习Icon组件
    4.学习actions

    在这里插入图片描述

    六、初识楼层

    课程目标

    1. 深入掌握VueX
    2. 深入掌握组件化思想
    3. 搭建楼层页面框架

    知识点

    1.VueX之actions

    actions是写异步函数的地方,通过异步请求获取数据。函数的第一个参数是context,context里包含state、commit等。通过commit把获取的数据提交给mutations,然后更新state。这是VueX给咱们设计出来的一套语法格式。

    import Vue from 'vue'
    import Vuex from 'vuex'
    import Api from '../api'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        title: '小米书城',
        list: [],
      },
      mutations: {
        setState(state, payload) {
          state[payload.key] = payload.value
        }
      },
      actions: {
        getList({ commit }) {
          Api.list().then(res => {
            if (res.code === 200) {
              commit({ type: 'setState', key: 'list', value: res.data })
            }
          })
        }
      }
    })
    

    actions里的函数并不会自动触发,可以在组件挂载后这个生命周期里手动触发。

      mounted() {
        this.$store.dispatch({ type: 'getList' })
      }
    

    2.初始楼层页面

    通过计算属性可以获取仓库里的数据。无论是哪个组件,都可以随时随地的获得仓库里的数据。我们在首页里使用两个组件,一个是侧边栏,另一个是列表。点击侧边栏的菜单可以控制列表滚动到对应的数据位置,同时右侧数据滚动时,侧边栏菜单的高亮也会有所变化,其实就是楼层的效果!

    这是首页的代码,可以清醒的看到使用了侧边栏组件和列表组件,以及在挂载完这个生命周期派发了getList这个action去请求数据

    <template>
      <div class="m-main m-home">
        <Sidebar></Sidebar>
        <List></List>
      </div>
    </template>
    
    <script>
    import Sidebar from '../components/Sidebar'
    import List from '../components/List'
    
    export default {
      components: {
        Sidebar,
        List
      },
      mounted() {
        this.$store.dispatch({ type: 'getList' })
      }
    }
    </script>
    

    3.侧边栏组件

    侧边栏里有菜单,菜单的数据需要从仓库里获得,仓库里的list数据是一个数组。

    在这里插入图片描述

    我们需要使用v-for把数组里的第一层的title字段渲染成菜单,并给每一个菜单菜单绑定点击事件,通过点击事件控制仓库里的currentId,该字段和菜单的高亮有关。

    <template>
      <div class="m-sidebar">
        <div 
          v-for="item in list" 
          :key="item.id" 
          class="m-sidebar-item" 
          :class="currentId === item.id ? 'active' : ''"
          @click="handleNav(item.id)">{{item.title}}</div>
      </div>
    </template>
    
    <script>
    let timer
    
    export default {
      computed: {
        list() {
          return this.$store.state.list
        },
        currentId() {
          return this.$store.state.currentId
        }
      },
      methods: {
        handleNav(id) {
          this.$store.commit({ type: 'setState', key: 'currentId', value: id })
        }
      }
    }
    </script>
    

    4.List组件

    List组件这节课并不讲太多内容,先渲染一下列表即可!渲染的时候需要注意一下这是一个两层的数组,第一层是分类,第二层是分类对应的列表。

    <template>
      <div class="m-list">
        <div v-for="categroy in list" :key="categroy.id" :id="categroy.id" class="m-category js-category">
          <div class="m-category-title">{{categroy.title}}</div>
          <div v-for="book in categroy.list" :key="book.id" class="m-list-item">
            <div class="m-info">
              {{book.title}}
            </div>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      computed: {
        list() {
          return this.$store.state.list
        }
      },
    }
    </script>
    

    授课思路

    在这里插入图片描述

    案例作业

    1.编辑actions函数并把返回的数据保存到仓库
    2.搭建楼层页面框架
    3.开发侧边栏组件并添加高亮
    4.开发列表组件

    在这里插入图片描述

  • 相关阅读:
    echarts的整理
    socket.io做一个简单的聊天案例
    WebSocket通信随笔
    接口返回的二维码图片,如何处理显示(axios处理后台返回图片流格式数据)
    小程序封装request请求
    一站式解决Vue插件开发,上传Github,Npm包发布
    微信公众号链接处理问题
    git常用命令
    vscode 常用配置
    项目中报错Cannot read property 'getAttribute' of undefined解决
  • 原文地址:https://www.cnblogs.com/xutongbao/p/14876300.html
Copyright © 2020-2023  润新知