• Vue2速成手册(原创不易,转载请注明出处)


    文章目录

    Vue速成手册

    0 前言

    本文使用的是Vue2.6.14

    • 环境如下:
    C:\Users\z004abwh>node -v
    v16.14.2
    
    C:\Users\z004abwh>npm -v
    8.5.0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • IDE

      • Vscode
      • 插件Vetur、ES6、HTML和CSS等基础插件
    • 调试工具

      vue devtools

      两种安装方式:

      • 第一种:github下载zip包,

        https://github.com/vuejs/devtools#vue-devtools
        
        • 1

        最新版本的调试工具要用yarn命令

        npm install -g yarn

        解压从github上下载的vue-devtools,进入目录

        执行:yarn install

        执行:yarn run build

        最后把打包的结果导入到浏览器的扩展程序中

      • 第二种:直接在一个空目录中使用npm i vue-devtools(亲测可用)

        在vue-devtools文件夹下:shells>chrome>manifest.json,将配置里的persistent的值修改为true;

        打开chrome,进入扩展程序管理界面(chrome://extensions/),加载已解压的扩展程序。选择vue-devtools>shells>chrome。加载完成就会出现以下的Vue.js devtools扩展程序。然后重启浏览器,再打开vue项目页面就可以在chrome的Devtools(就是console的那一栏,一般都排在最后面的。)找到Vue面板了。

    1 基础篇

    项目的目录结构:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YzZauMtX-1663494649201)(D:\markdown\Vue速成手册.assets\image-20220720104855387.png)]

    1.1 Hello world

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    
    <div id="app">
        
        {{ message }}
    div>
    
    <script src="./vue.js">script>
    <script>
    <!--    实例化一个Vue对象-->
        const vm = new Vue({
            // 挂在一个容器
            el: "#app",
            // 创建组件内的数据
            data: {
                message: "Hello Vue 2.6.14"
            }
        })
    
    script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    浏览器调试窗口预留:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1EJGdfUx-1663494649202)(D:\markdown\Vue速成手册.assets\image-20220720104954011.png)]

    1.1.1 小结

    • 想让Vue工作,必须要创建一个Vue实例,Vue构造函数接收一个唯一参数就是配置对象。
    • app这个div内依然遵守html规范,只是扩展了一些Vue语法
    • id为app这个div被称为Vue的模板
    • Vue实例和容器是一一对应的
    • 真实开发中,一个项目一般只会有一个Vue实例,Vue实例配合组件一起使用
    • data中的数据改变,模板中使用data的位置会自动更新

    1.2 模板语法

    vue中的模板语法分为两大类

    • 插值语法
      • 用于解析标签内容
      • 写法:{{ xxx }}, xxx是js表达式,可以直接读取到data中的所有区域

    1.3 v-bind数据绑定

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-bind数据绑定title>
    head>
    <body>
    <div id="app">
    
        <input type="text" v-bind:value="message"> <br><br>
    
        <input type="text" :value="message">
    div>
    
    <script src="./vue.js">script>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                message: "数据绑定"
            }
        })
    script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    1.4 v-model双向数据绑定

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>v-bind数据绑定title>
    head>
    <body>
    <div id="app">
    
        <input type="text" v-model:value="message"> <br><br>
    div>
    
    <script src="./vue.js">script>
    <script>
        const vm = new Vue({
            el: "#app",
            data: {
                message: "数据绑定"
            }
        })
    script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    1.5 el的两种写法

    • 第一种写法:el做为Vue构造函数的参数对象中的一个key,其值是一个符合css选择器的一个容器

      const vm = new Vue({
          el: '#app'
      })
      
      • 1
      • 2
      • 3
    • 第二种写法:先创建Vue实例,最后通过vm.$mount(‘#app’) 挂载对象

      const vm = new Vue({})
      vm.$mount('#app')
      
      • 1
      • 2

    1.6 data的两种写法

    • 对象形式

      const vm = new Vue({
      	el: '#app', 
      	data: {
      		message: "hello"
      	}
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • 函数形式(在组件中必须是函数形式的)

      const vm = new Vue({
      	el: '#app', 
      	// 正常写法
          data: function(){
      		return {
      			message: "hello world"
      		}
      	}
      	// 简写形式
      	data(){
      		return {
      			message: "hello world"
      		}
      	}
      	// 错误写法
      	data: ()=>{
                  console.log(this) # 这个this指向的是Window 
                  return{message: 'Hello'}
              }
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      由Vue管理的函数,一定不要写箭头函数,否则this指向就不再是Vue实例了

    1.7 MVVM 模型

    img

    • M-Model 指data中的数据

    • V-View 指模板

    • VM-ViewModel 视图模型,Vue实例

    • vm对象

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-knIl6gzX-1663494649202)(D:\markdown\Vue速成手册.assets\image-20220720120634191.png)]

      vm对象里面的属性和其原型对象上面的属性都可以在模板中直接使用。

    1.8 数据代理的本质

    1.8.1 JS基础知识复习

    Object对象是原型链的尽头,也可以说是所有对象的超类,在Object对象上有一个defineProperty方法。下面看下这个方法的具体使用流程:

    // 定义一个临时变量,初始化为空
    let temp = ''
    // 定义一个对象,设置两个属性分别是name和age
    let obj = {
        name: '张三',
        age: 18
    }
    // 调用Object的defineProperty方法
    // 1 参数1: 是需要监听的对象
    // 2 参数2: 是需要监听的对象里面的某一个属性
    // 3 参数3: 用于定制get方法和set方法,get方法的返回值是obj.xxx的结果值,set方法接收一个参数,这个参数是obj.xxx = yyy 中的yyy
    Object.defineProperty(obj, 'name', {
        
        get(){
            console.log('obj的name属性被读取了')
            return '小乌龟'
        },
        set(value){
            console.log('obj的name属性被改写了')
            temp = value
        }
    })
    // 改变name属性的值
    obj.name = '张无忌' // 输出: obj的name属性被改写了
    // 临时变量被赋值
    console.log(temp)  // 输出: 张无忌
    // 获取对象属性值方法一
    console.log(obj['name']) // 输出: obj的name属性被读取了  小乌龟
    // 获取对象属性值方法二
    console.log(obj.name)    // 输出: obj的name属性被读取了  小乌龟
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 一个对象代理另一个对象的读和写
     let obj1 = {
          name: '张三',
          age: 19
      }
      let obj2 = {
          name: '里斯',
          age: 24
      }
      Object.defineProperty(obj1, 'name', {
          get(){
              return obj2.name
          },
          set(value){
              obj2.name = value
          }
      })
    
      Object.defineProperty(obj1, 'age', {
          get(){
              return obj2.age
          },
          set(value){
              obj2.age = value 
          }
      })
    /*
    	测试代码
    	obj1.name
        '里斯'
        obj1.age
        24
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    1.8.2 vue中数据代理的解读

    vue中的数据代理是通过vm对象来代理data对象中属性的操作

    使用vm对象代理data对象的好处是更方便,在模板中可以直接操作data中的数据,在vm实例中可以通过this.xxx直接获取到xxx属性。

    new Vue({…})创建vm实例成功后,会把data中的值赋值到vm的_data属性下,vm.xxx本质上会调用vm._ _ data.xxx,_ data.xxx又会调用defineProperty的get()方法,进行实现使用vm对象代理data对象的行为。

    img

    • 通过object.defineProperty()把data中所有属性添加到vm上
    • 为每一个添加到vm上的属性都指定一个setter和getter
    • 在getter、setter内部去操作data中对象的属性
    • vue将data中的数据拷贝一份到_data属性中,又将_data里面的属性提到Vue实例中,通过defineProperty实现数据代理,通过getter、setter操作属性,进而操作_data中的属性,_ _ data对data进行数据劫持,实现响应式。

    1.9 处理事件

    1.9.1 基础用法

    • 以点击事件为例演示Vue中如何绑定事件

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>绑定事件练习</title>
      </head>
      <body>
      
      <div id="app">
          <!--    v-on普通写法-->
          <button v-on:click="test">绑定事件练习</button>
          <!--    v-on简单写法-->
          <button @click="test">绑定事件简单写法</button>
          <!--    参数传递@click="sendParams"等价于@click="sendParams($event)" $event保存着绑定的事件-->
          <button @click="sendParams">绑定事件默认传参</button>
          <!--    如果有多个参数-->
          <button @click="sendMultiParams($event, 123)">绑定事件传递多个参数</button>
      </div>
      
      <script src="./vue.js"></script>
      <script>
          const vm = new Vue({
              el: '#app',
              data: {
                  msg: 'hello'
              },
              methods: {
                  test() {
                      alert(this.msg)
                  },
                  sendParams(e) {
                      console.log(e) // 输出点击事件
                  },
                  sendMultiParams(e, x) {
                      console.log(e) // 输出点击事件
                      console.log(x) // 输出123
                  }
              }
          })
      </script>
      </body>
      </html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 简单总结一下:

        • 绑定事件的正常写法: v-on:event = “callback”; 绑定事件的简单写法:@event = “callback”

        • @click=“callback” 等价于 @click=“callback($event)” ,如果回调不需要传其他参数那么前面的两种写法都可以

        • 如果回调需要用到事件对象和其他参数,那必须这样写:@click=“callback($event, args)”

        • 回调函数定义在methods上

    • methods函数中的this指向问题

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>methods中this的指向问题</title>
      </head>
      <body>
      <div id="app">
          <button @click="getMsg">获取data中的msg</button>
          <button @click="getMsg2" style="background-color: red">获取data中的msg</button>
      </div>
      <script src="./vue.js"></script>
      
      <script>
          msg = '全局我最大'
      
          const vm = new Vue({
              el: '#app',
              data: {
                  msg: '嘻嘻哈哈好开心'
              },
              methods: {
                  getMsg: function () {
                      console.log(this)     // 输出 : Vue实例对象 也就是vm
                      console.log(this.msg) // 输出 : 嘻嘻哈哈好开心
                  },
                  getMsg2: () => {
                      console.log(this)     // 输出:Window 全局对象
                      console.log(this.msg) // 输出: 全局我最大
                  }
              }
      
          })
      </script>
      </body>
      </html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 简单总结:
        • methods中定义的函数最终会出现在vm对象或者组件实例对象中
        • methods中的函数必须使用普通的函数定义方式,不可以使用箭头函数,如果使用箭头函数,会改变函数内this的指向

    1.9.2 常用事件修饰符

    • prevent 阻止默认事件
    • stop 阻止事件冒泡
    • once 事件只触发一次
    • capture 使用事件的捕获模式
    • self 只有event.target是当前操作的元素才触发事件
    • passtive 事件的默认行为立即执行,无需等待事件回调执行完毕

    事件描述符可以连续写

    DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8" />
        <title>事件修饰符title>
        
        <script type="text/javascript" src="../js/vue.js">script>
        <style>
          * {margin-top: 20px;}
          .demo1 {height: 50px;background-color: skyblue;}
          .box1 {padding: 5px;background-color: skyblue;}
          .box2 {padding: 5px;background-color: white;}
          .list {width: 200px;height: 200px;background-color: skyblue;overflow: auto;}
          li {height: 100px;}
        style>
      head>
      <body>
    
        <div id="root">
          <h2>欢迎来到{{ name }}学习h2>
          
          <a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息a>
    
          
          <div class="demo1" @click="showInfo">
            <button @click.stop="showInfo">点我提示信息button>
            
            
          div>
    
          
          <button @click.once="showInfo">点我提示信息button>
    
          
          <div class="box1" @click.capture="showMsg(1)">
            div1
            <div class="box2" @click="showMsg(2)">
              div2
            div>
          div>
    
          
          <div class="demo1" @click.self="showInfo">
            <button @click="showInfo">点我提示信息button>
          div>
    
          
          
          
          <ul @wheel.passive="demo" class="list">
            <li>1li>
            <li>2li>
            <li>3li>
            <li>4li>
          ul>
        div>
    
        <script type="text/javascript">
          Vue.config.productionTip = false
    
          new Vue({
            el: '#root',
            data: {
              name: '尚硅谷'
            },
            methods: {
              showInfo(e) {
                alert('同学你好!')
                // console.log(e.target)
              },
              showMsg(msg) {
                console.log(msg)
              },
              demo() {
                for (let i = 0; i < 100000; i++) {
                  console.log('#')
                }
                console.log('累坏了')
              }
            }
          })
        script>
      body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    1.9.3 监听键盘事件

    • Vue定制的常用按键别名

      • enter 回车
      • delete 删除
      • esc 退出
      • space 空格
      • up
      • down
      • left
      • right
      • tab 必须配合keydown使用
    • 自定义按键别名

      Vue.config.KeyCodes.自定义键名 = 键码
      
      • 1
    • 案例

      DOCTYPE html>
      <html>
        <head>
          <meta charset="UTF-8" />
          <title>键盘事件title>
          
          <script type="text/javascript" src="../js/vue.js">script>
        head>
        <body>
      
          <div id="root">
            <h2>欢迎打开{{name}}笔记h2>
            <input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo"><br/>
            <input type="text" placeholder="按下tab提示输入" @keydown.tab="showInfo"><br/>
            <input type="text" placeholder="按下回车提示输入" @keydown.huiche="showInfo"><br/>
          div>
      
          <script type="text/javascript">
            Vue.config.productionTip = false	// 阻止 vue 在启动时生成生产提示。
            Vue.config.keyCodes.huiche = 13		// 定义了一个别名按键
      
            new Vue({
              el: '#root',
              data: {
                name: 'cess'
              },
              methods: {
                showInfo(e) {
                  // console.log(e.key,e.keyCode)
                  console.log(e.target.value)
                }
              },
            })
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36

    1.10 计算属性

    1.10.1 一个小例子引入计算属性

    • 使用插值表达式实现:

      
      
      
          
          计算属性引入小例子
      
      
      
      
      first name:
      last name:

      full name: {{ firstName + '-' + lastName }}

      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
    • 使用methods实现:

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>计算属性引入小例子title>
      head>
      <body>
      
      <div id="app">
          first name: <input type="text" v-model:value="firstName"/> <br>
          last name: <input type="text" v-model:value="lastName"/>
          <h3 style="color: red">full name: {{ getFullName() }}h3>
      
      
      div>
      
      <script src="./vue.js">script>
      <script>
          Vue.config.productionTip = false
          const vm = new Vue({
              el: '#app',
              data: {
                  firstName: '张',
                  lastName: '三',
              },
              methods: {
                  getFullName() {
                      console.log('@getFullName被执行了。。。')
                      return this.firstName + this.lastName
                  },
              }
          })
      
      script>
      
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
    • 使用计算属性写法

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>计算属性引入小例子title>
      head>
      <body>
      
      <div id="app">
          first name: <input type="text" v-model:value="firstName"/> <br>
          last name: <input type="text" v-model:value="lastName"/>
          <h3 style="color: green">full name: {{ fullName }}h3>
      div>
      
      <script src="./vue.js">script>
      <script>
          Vue.config.productionTip = false
          const vm = new Vue({
              el: '#app',
              data: {
                  firstName: '张',
                  lastName: '三',
              },
              computed: {
                  // 完整写法
                  fullName: {
                      get() {
                          return this.firstName + '-' + this.lastName
                      },
                      set(value) {
                          let arr = value.split('-')
                          this.firstName = arr[0]
                          this.lastName = arr[1]
                      }
                  }
                  // 如果只是获取数据,那么可以直接使用简写方式
                  fullName(){
              		return this.firstName + '-' + this.lastName
          		}
              }
          })
      
      script>
      
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46

    1.10.2 计算属性小结

    计算属性一般用于通过已知属性计算获取到的值,例如上面的例子。姓名都是已经的属性。连接起来获取全名

    计算属性的原理也是利用Object.defineProperty()方法提供的getter和setter

    get函数初次读取时执行一次,数据变化时执行一次

    与methods相比,计算属性有缓存机制,数据不变化就不会更新

    计算属性会出现在vm实例对象上,可以直接在模板中像data中的数据一样使用

    如果需要改变计算属性,并响应式的更新页面,那么需要设计set方法,如果不需要修改计算属性和其相关的属性,那么使用简写格式是最好用的。

    1.11 侦听属性watch用法

    watch监视属性用于监视属性的变化,当属性发生变化时,回调函数自动被调用。

    监视的属性必须存在才能被监视,可以是data里面的属性也可以是计算属性

    监视属性同样具有两种写法:

    • 第一种是在配置对象中直接传入
    • 第二种是使用vm实例的$watch函数

    1.11.1 watch基本用法

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>watch用法title>
    head>
    <body>
    <div id="app">
        <h3>好好 {{ msg }}h3>
        <button @click="changeStatus">切换状态button>
    div>
    
    <script src="./vue.js">script>
    
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                flag: true,
                msg: ''
            },
            methods: {
                changeStatus() {
                    this.flag ? this.msg = '学习' : this.msg = '玩耍'
                    this.flag = !this.flag
                }
            },
            // 监视属性,key必须是watch,vue中已经写死,value是一个对象
            watch: {
                // 监视的属性,可以是data也可以是计算属性,当被监视的属性发生变化时,handler函数会被调用
                msg: {
                    // 内部钩子函数,接收两个值,分别是修改后的值和修改前的值
                    handler(newVal, oldVal) {
                        console.log('msg被修改了', newVal, oldVal)
                    }
                }
            }
        })
    script>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 计算属性的简写方式

      		/*前面省略*/
      		watch: {
                  msg(newVal, oldVal){
                      console.log('msg被修改了', newVal, oldVal)
                  }
              }
              /*后面省略*/
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 如果想加载时就执行一次,那么需要配置immediate属性

         		 /*前面省略*/
      		watch: {
                  msg: {
                      immediate: true,  //加载完成就触发一次
                      handler(newVal, oldVal) {
                          console.log('msg被修改了', newVal, oldVal)
                      }
                  }
              }
               /*后面省略*/
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HFuLA8wM-1663494649203)(D:\markdown\Vue速成手册.assets\image-20220721110751321.png)]

      加载时候就执行了一次监听属性的回调函数,这时候未修改时候的值是undefined。

    1.11.2 监视复杂对象

    在js中对象和数组属于复杂对象,复杂对象的值是一个指针,指向的是堆中的地址,修改复杂对象内部的值并不会改变对象本身,所以也就不会触发监视属性。

    • 监视复杂对象的错误写法

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>watch深度监视案例title>
      head>
      <body>
      
      <div id="app">
          <h1>个人信息h1>
          <input type="text" :value="person.name">
          <input type="text" :value="person.age"/>
          <button @click="changeName">修改姓名button>
          <button @click="changeAge">修改年龄button>
      div>
      
      <script src="./vue.js">script>
      <script>
          const vm = new Vue({
              el: '#app',
              data: {
                  person: {
                      name: '张三',
                      age: 12
                  }
              },
              methods: {
                  changeName() {
                      this.person.name = 'lisi'
                  },
                  changeAge() {
                      this.person.age = 99
                  },
              },
              watch: {
                  person: {
                      handler(newValue, oldValue) {
                          console.log('person被修改了' + '新值是:' + newValue + '老值是:' + oldValue)
                      }
                  }
              }
      
          })
      script>
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ju1c6FXJ-1663494649204)(D:\markdown\Vue速成手册.assets\image-20220721112249335.png)]

      无论怎么点击按钮,handler回调都不会执行。

    • 监视复杂对象的正确写法1

      		watch: {
                  'person.name': {
                      handler(newValue, oldValue) {
                          console.log('person.name被修改了' + '新值是:' + newValue + '老值是:' + oldValue)
                      }
                  },
                  'person.age': {
                      handler(newValue, oldValue) {
                          console.log('person.age被修改了' + '新值是:' + newValue + '老值是:' + oldValue)
                      }
                  }
      
              }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o2Pn9EES-1663494649204)(D:\markdown\Vue速成手册.assets\image-20220721112442174.png)]

    • 监视复杂对象的正确写法2

      		watch: {
                  person: {
                      deep: true,
                      handler(newValue, oldValue) {
                          console.log('person.name被修改了' + '新值是:' + newValue.name + '老值是:' + oldValue.name)
                          console.log('person.age被修改了' + '新值是:' + newValue.age + '老值是:' + oldValue.age)
                      }
                  },
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      deep属性可以监听到复杂对象内部的数据

    1.12 计算属性与侦听属性的区别

    1.12.1 小实例讲解计算属性与侦听属性

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ffnji6u6-1663494649204)(D:\markdown\Vue速成手册.assets\image-20220721114031722.png)]

    • 使用计算属性实现:

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>计算属性与侦听属性的用法比对title>
      head>
      <body>
      <div id="app">
          <input type="text" v-model:value="firstName"> <br>
          <input type="text" v-model:value="lastName">
          <h3>{{ fullName }}h3>
      div>
      <script src="./vue.js">script>
      <script>
          const vm = new Vue({
              el: '#app',
              data: {
                  firstName: '张',
                  lastName: '三'
              },
              computed: {
                  fullName(){
                      return this.firstName + '-' + this.lastName
                  }
              }
      
          })
      script>
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30

      这里的代码不做过多的解释,很基础的实现过程。

    • 使用侦听属性实现:

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>计算属性与侦听属性的用法比对title>
      head>
      <body>
      <div id="app">
          <input type="text" v-model:value="firstName"> <br>
          <input type="text" v-model:value="lastName">
          <h3>{{ fullName }}h3>
      div>
      <script src="./vue.js">script>
      <script>
          const vm = new Vue({
              el: '#app',
              data: {
                  firstName: '张',
                  lastName: '三',
                  fullName: '张-三'
              },
              // computed: {
              //     fullName(){
              //         return this.firstName + '-' + this.lastName
              //     }
              // }
              watch: {
                  firstName(newVal){
                      this.fullName = newVal + this.lastName
                  },
                  lastName(newVal){
                      this.fullName = this.firstName + newVal
                  }
              }
          })
      script>
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38

    1.12.2 更新一下需求

    我现在的需求是,如果名字更新那么全名立即更新,如果是姓更新了,等一秒钟再更新全名,更新需求后发现用计算属性很难实现了

    • 用侦听属性实现:

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>计算属性与侦听属性的用法比对title>
      head>
      <body>
      <div id="app">
          <input type="text" v-model:value="firstName"> <br>
          <input type="text" v-model:value="lastName">
          <h3>{{ fullName }}h3>
      div>
      <script src="./vue.js">script>
      <script>
          const vm = new Vue({
              el: '#app',
              data: {
                  firstName: '张',
                  lastName: '三',
                  fullName: '张-三'
              },
              // computed: {
              //     fullName(){
              //         return this.firstName + '-' + this.lastName
              //     }
              // }
              watch: {
                  firstName(newVal) {
                      setTimeout(() => {
                          this.fullName = newVal + this.lastName
                      }, 1000)
                  },
                  lastName(newVal) {
                      this.fullName = this.firstName + newVal
                  }
              }
          })
      script>
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40

    1.12.3 小结

    • 计算属性和侦听属性的对比

      • 计算属性

        计算属性能完成的功能,侦听属性都可以完成

      • 侦听属性

        侦听属性能够完成的功能,计算属性不一定能完成,比如实现一些异步操作,在一个属性修改1s后执行一个动作。

    • 关于this指向的小总结,极其重要

      • 所有Vue管理的函数,最好写成普通函数,这样this指向的是vm或者是组件实例对象
      • 所有不被Vue管理的函数,比如定时器函数,ajax回调函数,promise回调函数等,最好写成箭头函数,这样this的指向还是vm或者组件实例对象。

    1.13 使用v-bind绑定样式

    通过v-bind绑定任意dom元素的class属性,通过对class属性赋值

    绑定样式的写法:

    :class = 'xxx'  // xxx可以是字符串、数组、对象
    
    • 1
    • 字符串写法用于:类名不确定、要动态获取
    • 数组写法用于:要绑定多个样式,个数也不确定,名字也不确定
    • 对象写法用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用

    也可以直接绑定dom元素的style属性

    :style="[a,b]" // 其中a,b是样式对象
    :style="{fontSize: xxx}" 其中xxx是动态值
    
    
    • 1
    • 2
    • 3

    示例代码:

    <style>
      .basic {width: 300px;height: 50px;border: 1px solid black;}
      .happy {border: 3px solid red;background-color: rgba(255, 255, 0, 0.644);
        background: linear-gradient(30deg, yellow, pink, orange, yellow);}
      .sad {border: 4px dashed rgb(2, 197, 2);background-color: skyblue;}
      .normal {background-color: #bfa;}
      .atguigu1 {background-color: yellowgreen;}
      .atguigu2 {font-size: 20px;text-shadow: 2px 2px 10px red;}
      .atguigu3 {border-radius: 20px;}
    style>
    
    <div id="root">
      
      <div class="basic" :class="mood" @click="changeMood">{{name}}div><br/><br/>
    
      
      <div class="basic" :class="classArr">{{name}}div><br/><br/>
    
      
      <div class="basic" :class="classObj">{{name}}div><br/><br/>
    
      
      <div class="basic" :style="styleObj">{{name}}div><br/><br/>
    
      
      <div class="basic" :style="styleArr">{{name}}div>
    div>
    
    <script type="text/javascript">
      Vue.config.productionTip = false
    
      const vm = new Vue({
        el: '#root',
        data: {
          name: '尚硅谷',
          mood: 'normal',
          classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
          classObj: {
            atguigu1: false,
            atguigu2: false,
          },
          styleObj: {
            fontSize: '40px',
            color: 'red',
          },
          styleObj2: {
            backgroundColor: 'orange'
          },
          styleArr: [
            {
              fontSize: '40px',
              color: 'blue',
            },
            {
              backgroundColor: 'gray'
            }
          ]
        },
        methods: {
          changeMood() {
            const arr = ['happy', 'sad', 'normal']
            const index = Math.floor(Math.random() * 3)
            this.mood = arr[index]
          }
        },
      })
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    1.14 条件渲染

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>条件渲染title>
    head>
    <body>
    <div id="app">
        <h1>打分系统h1>
        <label for="number">分数:label>
        <input type="text" v-model:value="number" id="number">
        <button @click="getRandomNumber">获取分数button>
        <br>
        <hr>
        <p>等级:p>
        <p v-if="number>=80">Ap>
        <p v-else-if="number<80 && number>=60">Bp>
        <p v-else-if="number<60 && number>=40">Cp>
        <p v-else>Dp>
    div>
    <script src="./vue.js">script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                number: 0,
            },
            methods: {
                getRandomNumber() {
                    this.number = Math.round(Math.random(1, 100) * 100)
                }
            }
        })
    script>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 小结

      • 写法

        v-if = "表达式"
        v-else-if = "表达式"
        v-else
        
        • 1
        • 2
        • 3
      • v-if 与v-show的区别

        v-if 会直接操作dom元素,直接删除dom元素,v-if用于切换不频繁的场景
        v-show 不会直接操作dom元素,v-show操作的是display属性,不会直接操作dom元素,用于频繁切换的场景
        
        • 1
        • 2
      • 如果需要使用template标签对整块结构进行操作,那么只支持v-if,不支持v-show

        DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>v-if与v-showtitle>
        head>
        <body>
        <div id="app">
           
          <template v-if="isShow">
              <p>静夜思p>
              <br>
              <p>窗前明月光p>
              <p>疑是地上霜p>
              <p>举头望明月p>
              <p>低头思故乡p>
          template>
            <button @click="show"> 显示/隐藏 button>
        div>
        <script src="./vue.js">script>
        <script>
          const vm = new Vue({
              el: '#app',
              data: {
                  isShow: true
              },
              methods: {
                  show(){
                      this.isShow = !this.isShow
                  }
              }
          })
        script>
        body>
        html>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35

    1.15 v-for

    v-for用于遍历数组、对象、字符串

    • 语法:

      <li v-for=(item, index) of items :key="index">li>
      
      • 1
    • 示例代码

      <title>基本列表title>
      <script type="text/javascript" src="../js/vue.js">script>
      
      <div id="root">
        
        <h3>人员列表(遍历数组)h3>
        <ul>
          <li v-for="(p,index) of persons" :key="index">{{ p.name }}-{{ p.age }}li>
        ul>
      
        
        <h3>汽车信息(遍历对象)h3>
        <ul>e
          <li v-for="(value,k) of car" :key="k">{{ k }}-{{ value }}li>
        ul>
      
        
        <h3>测试遍历字符串(用得少)h3>
        <ul>
          <li v-for="(char,index) of str" :key="index">{{ char }}-{{ index }}li>
        ul>
      
        
        <h3>测试遍历指定次数(用得少)h3>
        <ul>
          <li v-for="(number,index) of 5" :key="index">{{ index }}-{{ number }}li>
        ul>
      div>
      
      <script type="text/javascript">
        Vue.config.productionTip = false
        new Vue({
          el: '#root',
          data: {
            persons: [
              { id: '001', name: '张三', age: 18 },
              { id: '002', name: '李四', age: 19 },
              { id: '003', name: '王五', age: 20 }
            ],
            car: {
              name: '奥迪A8',
              price: '70万',
              color: '黑色'
            },
            str: 'hello'
          }
        })
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48

      image.png

    1.15.x key原理 diff算法 vm.$set() api的用法

    待补充

    1.16 收集表单数据

    • 表单类型

      • text :v-model收集value值
      • radio:value值
      • checkbox :
        • 没有配置value属性, 那么收集的是checked属性(勾选与未勾选,是布尔值)
        • 如果配置value属性:
          • v-model的初始值是非数组,那么收集的是checked属性(勾选或者未勾选,布尔型)
          • v-model的初始值是数组,那么收集的就是value组成的数组
    • v-model 修饰符

      • lazy 失去焦点后再收集数据
      • number 输入字符串转换成有效的数字
      • trim 输入首尾空格过滤
    • 收集表单示例

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>使用v-model收集表单数据title>
      head>
      <body>
      
      <div id="root">
          <form @submit.prevent="demo">
              账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
              密码:<input type="password" v-model="userInfo.password"> <br/><br/>
              年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
              性别:
              男<input type="radio" name="sex" v-model="userInfo.sex" value="male"><input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
              爱好:
              学习<input type="checkbox" v-model="userInfo.hobby" value="study">
              打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
              吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
              <br/><br/>
              所属校区
              <select v-model="userInfo.city">
                  <option value="">请选择校区option>
                  <option value="beijing">北京option>
                  <option value="shanghai">上海option>
                  <option value="shenzhen">深圳option>
                  <option value="wuhan">成都option>
              select>
              <br/><br/>
              其他信息:
              <textarea v-model.lazy="userInfo.other">textarea> <br/><br/>
              <input type="checkbox" v-model="userInfo.agree">阅读并接受
              <a href="https://www.yuque.com/cessstudy">《用户协议》a>
              <button>提交button>
          form>
      div>
      
      <script src="./vue.js">script>
      
      <script type="text/javascript">
          Vue.config.productionTip = false
      
          new Vue({
              el: '#root',
              data: {
                  userInfo: {
                      account: '',
                      password: '',
                      age: 18,
                      sex: 'female',
                      hobby: [],
                      city: 'beijing',
                      other: '',
                      agree: ''
                  }
              },
              methods: {
                  demo() {
                      console.log(JSON.stringify(this.userInfo))
                  }
              }
          })
      script>
      
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67

    1.17 自定义过滤器(vue3将移除)

    对需要再模板中显示的数据进行特定格式化后再显示,适合做一些简单的逻辑

    • 注册过滤器

      • 全局过滤器

        Vue.filter(name, callback) 全局过滤器
        
        • 1
      • 局部过滤器

        new Vue({
        	filters: {
        		name: callback
        	}
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
    • 使用过滤器

      {{ xxx | 过滤器名 }}
      
      v-bind:属性名 = ”xxx | 过滤器名“ 
      
      • 1
      • 2
      • 3

      过滤器可以接收额外参数,多个过滤器可以串联

      并不是改变源数据,而是产生新的数据用于模板的展示

    • 代码示例

      DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8" />
        <title>过滤器title>
        <script type="text/javascript" src="./vue.js">script>
        <script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js">script>
      head>
      <body>
      <div id="root">
        <h2>时间h2>
        <h3>当前时间戳:{{time}}h3>
        <h3>转换后时间:{{time | timeFormater()}}h3>
        <h3>转换后时间:{{time | timeFormater('YYYY-MM-DD HH:mm:ss')}}h3>
        <h3>截取年月日:{{time | timeFormater() | mySlice}}h3>
      div>
      body>
      
      <script type="text/javascript">
        Vue.config.productionTip = false
        // 全局过滤器
        Vue.filter('mySlice',function(value){
          return value.slice(0,11)
        })
        new Vue({
          el:'#root',
          data:{
            time:1626750147901,
          },
          // 局部过滤器
          filters:{
            timeFormater(value, str="YYYY年MM月DD日 HH:mm:ss"){
              return dayjs(value).format(str)
            }
          }
        })
      script>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38

    1.18 vue内置指令小结

    • v-bind

    • v-model

    • v-for

    • v-on

    • v-show

    • v-if

    • v-else-if

    • v-else

    • v-text

      • 向其所在的节点中渲染文本内容
      • 与插值语法的区别,v-text会直接替换掉dom元素中的其他内容,插值表达式可以拼接,更加灵活
    • v-html

      • v-html会解析html元素,可能造成xss攻击
      • v-html与插值表达式的区别也是前者可以替换掉dom中的内容
      • v-html与v-text的区别是前者可以解析html元素,后者不可以
    • v-cloak

      • 使用css配和v-cloak可以解决网速慢时页面展示出{{ xxx }} 的问题

      • 示例代码

        <title>v-cloak指令title>
        
        <style>
          [v-cloak] {
            display:none;
          }
        style>
        
        <div id="root">
          <h2 v-cloak>{{ name }}h2>
        div>
        
        // 够延迟5秒收到vue.js
        <script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js">script>
        
        <script type="text/javascript">
          console.log(1)
          Vue.config.productionTip = false
          new Vue({
            el:'#root',
            data:{name:'cess'}
          })
        script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
    • v-once

      • v-once所在的dom节点只在第一次动态渲染后,就视为静态内容了
      • 用于优化性能
    • v-pre

      • 跳过v-pre修饰的dom节点,不参与编译过程
      • 加快编译过程

    1.19 自定义Vue指令

    待补充

    1.20 vue生命周期与钩子函数

    这是vue基础的最后一个内容,也是vue中最重要的内容。

    生命周期.png

    1.20.1 小实例引入vue生命周期

    需求是这样的,我想打开网页就能看到文字具有动态效果。

    不使用vue周期函数的实现代码

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>练习生命周期title>
    head>
    <body>
    
    <div id="app">
        <h1 :style="{opacity: opacity}">欢迎就入魔鬼训练营h1>
    div>
    
    <script src="./vue.js">script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                opacity: 1
            },
        })
        setInterval(function () {
            if (vm.opacity>0) {
                vm.opacity -= 0.01
            } else {
                vm.opacity = 1
            }
        }, 16)
    script>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 缺点:
      • 每次打开界面都会创建一个定时器,定时器数量会越来越多,造成浏览器卡死。
      • vue外部使用vm也是不推荐的

    使用vue钩子的实现代码

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>练习生命周期title>
    head>
    <body>
    
    <div id="app">
        <h1 :style="{opacity: opacity}">欢迎就入魔鬼训练营h1>
    div>
    
    <script src="./vue.js">script>
    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                opacity: 1
            },
            mounted(){
                this.interval = setInterval(()=>{
                    if (vm.opacity > 0) {
                        vm.opacity -= 0.01
                    } else {
                        vm.opacity = 1
                    }
                }, 16)
            },
            beforeDestroy(){
                clearInterval(this.interval)
            }
        })
    script>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    1.20.2 小结

    常用的生命周期函数:

    • mounted发送ajax请求,启动定时器,绑定自定义事件,订阅消息等初始化操作
    • beforeDestroy清除定时器、解绑自定义事件,取消订阅消息等收尾工作

    关于销毁Vue实例:

    • 销毁后借助Vue开发者工具看不到任何信息
    • 销毁后自定义事件会失效,但原生dom事件依然有效
    • 一般不会在beforedestroy操作数据,因为即便操作数据,也不会再触发更新流程了

    2 组件化开发

    2.1 理解组件化

    2.1.1 概念理解

    • 模块
      • 在前端工程中模块一般指定一个.js文件,可以在js文件引入其他模块暴露的信息,模块是一个名词,用于描述一个单独的js文件
    • 模块化
      • 使用多文件js编写的项目就可以称为模块化的项目,模块化是一个形容词,用来形容项目
    • 组件(用于实现局部功能的代码和资源的集合)
      • 组件用于描述前端项目中的一块内容,组件具有一定的可复用性,类似于函数,可以通过传递参数的不同输出不同的结果
    • 组件化
      • 组件化同样是一个形容词,用于形容项目

    2.1.2 模块化编写项目的缺点

    在没有类似vue这种前端框架之前,我们都是用模块化编写的前端项目的,模块化开发的缺点是依赖关系混乱,不好维护,代码复用性不高,具有很高的耦合性,代码冗余。

    image.png

    组件化编程具有低耦合,代码复用率高等特点:

    image.png

    2.2 非单文件组件

    • 定义

      一个文件中包含有n个组件

    2.3 单文件组件

    • 定义

      一个文件中只有1个组件

    2.4 组件的基本使用

    使用组件的三大步骤

    1定义组件

    2注册组件

    3使用组件

    2.4.1 定义组件

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>创建组件title>
    head>
    <body>
    <div id="app">
        
        <h1>{{ title }}h1>
        <person>person>
        <hr>
        <dog>dog>
    div>
    
    <template id="cdog">
        <div>
            <h1>狗详细信息h1>
            <label for="dog-name">label>
            <input type="text" v-model:value="name" id="dog-name"> <br>
            <label for="dog-sex">label>
            <input type="text" v-model:value="sex" id="dog-sex">
            <button @click="showDogInfo">显示狗的信息button>
        div>
    template>
    
    <script src="../js/vue.js">script>
    <script>
        // 第一步: 创建组件
        const person = Vue.extend({
            template: `
              

    `
    , data() { return { name: '张三', age: 19 } }, methods: { showInfo() { alert(this.name + '-' + this.age) } } }) const dog = Vue.extend( { template: '#cdog', data() { return { name: '大黄', sex: '小公狗' } }, methods: { showDogInfo() { alert(this.name + '-' + this.sex) } } } ) // 第二步:注册组件,全局注册,对所有的vm都有效 Vue.component('person', person) const vm = new Vue({ el: '#app', data: { title: '人员详细信息' }, // 局部注册组件,只能在当前vm的容器内使用 components: { dog, } })
    script> body> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 对上面的案例简单总结:

      • 定义组件

        普通写法

        const component-name = Vue.extend({
        	
            data(){
        		return {
        			xxxx: 'yyyy'
        		}
        	}
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8

        简单写法

        const component-name = {
        	data(){},
        	methods: {}
        }
        
        • 1
        • 2
        • 3
        • 4

        Vue.extend传入的配置项于new Vue() 传入的配置项基本相同,有两点需要注意:

        Vue.extend中不能有el,因为所有的组件最终都会挂载到vm上面

        Vue.extend中的data必须写成函数形式的,不可以写成对象形式的

      • 注册组件

        • 全局注册

          Vue.component('组件名', 组件)
          //例如: 
          Vue.component('person', person) 
          // 组件名是最终在模板中使用的标签名
          
          • 1
          • 2
          • 3
          • 4
        • 局部注册

          new Vue({
          	'''
          	components: {
          		组件名: 组件
          	}
          })
          // 一般组件名与组件都会定义成一样的名字,所以在局部注册的时候一般会使用简写形式
          new Vue({
              ’‘’
              components: {
              	组件, 
          	}
          })
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
      • 使用组件

        • 用法1

          <组件名>组件名>
          
          • 1
        • 用法2 (需要脚手架支持,否则会有问题)

          <组件名/>
          
          • 1
    • 注意事项

      • 关于组件名

        • 如果是一个单词组成

          • 第一种写法(首字母小写):person
          • 第二种写法(首字母大写):Person
        • 如果是多个单词组成

          • 第一种写法(kebab-case命名): person-info
          • 第二种写法(CamelCase命名): PersonInfo
        • 特别注意

          • 组件名要尽可能回避html标签

          • 可以在定义组件时候使用name配置项指定组件在开发者工具中呈现的名字

            const cat = {
                    name: 'xiao-zhu-pei-qi',
                    template: '#ccat',
                    data(){
                        return {
                            msg: '我是一只小花猫'
                        }
                    }
                }
            
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9

            [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OyDDRgvZ-1663494649205)(D:\markdown\Vue速成手册.assets\image-20220722133451776.png)]

    2.5 组件的嵌套用法

    vm可以理解为所有组件的父组件,一个组件内部可以挂多个组件,组件是可以嵌套的,类似与数据结构中的树,vm类似于根节点

    img

    doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>组件嵌套title>
    head>
    <body>
    
    <div id="app">
        <app>app>
    div>
    
    <script src="../js/vue.js">script>
    <script>
    
        const student = {
            name: 'student',
            data() {
                return {
                    name: '张三',
                    age: 11
                }
            },
            template: `
              

    学生信息展示

    学生姓名: {{ name }}

    学生年龄: {{ age }}

    `
    , } const school = { name: 'school', data() { return { name: '家里蹲', address: '蹲家里' } }, template: `

    学校信息展示

    学校名称:{{ name }}

    学校地址:{{ address }}


    `
    , components: { student, } } const app = { name: 'app', template: `

    {{ title }}

    `
    , data() { return { title: 'app标题' } }, components: { school } } const vm = new Vue({ el: '#app', components: { app } })
    script> body> html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o4aug9T0-1663494649206)(D:\markdown\Vue速成手册.assets\image-20220722142336299.png)]

    2.6 关于VueComponent

    通过const school = Vue.extend({options}),会定义一个组件,school本质上是一个VueComponent构造函数

    当我们在模板中写 或者,Vue解析时会创建school的实例对象,Vue自动调用了new Component(options)

    每次调用Vue.extend,都会返回一个全新的VueComponent,不同的组件是不同的对象

    关于this指向:

    组件配置中data函数、methods中的函数、watch中的函数、computed中的函数他们的this均是VueComponent实例对象

    new Vue(options) 配置中:data函数或者对象、 methods中的函数、watch中的函数、computed中的函数他们的this均是Vue实例对象

    VueComponent实例对象简称vc, Vue实例对象简称vm

    组件实例对象vc可以访问到Vue原型上面的属性和方法

    **VueComponent.prototype. _ _ proto _ _ === Vue.prototype **

    image.png

    2.6.1 简单说一下prototype和 _ _ proto _ _

    _ _ proto _ _ 是对象特有的,负责对象的属性方法的查找,如果对象自身没有需要的属性或者方法,_ _ proto _ _会指向对象构造函数的原型对象, _ _ proto _ _的终点是null

    prototype 是函数特有的,但是因为js中函数也是一种特殊的对象,所以在函数中也有 _ _ proto _ _ 这是js原型结构中很难理解的地方

    2.7 单文件组件

    单文件组件就是一个文件只有一个组件,一个文件只完成局部的功能和包装局部的静态资源,vue中单文件组件的文件后缀是.vue

    定义vue中单文件组件的常规目录结构结构:

    Mode                 LastWriteTime         Length Name
    ----                 -------------         ------ ----
    -a----         2022/7/22     14:49            114 app.vue 
    -a----         2022/7/22     14:49            132 index.html
    -a----         2022/7/22     14:48              0 main.js
    -a----         2022/7/22     14:49            117 school.vue
    -a----         2022/7/22     14:49            118 student.vue
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • school.vue

      
      
      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
    • student.vue

      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    • App.vue

      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    • main.js

      import App from './App.vue'
      
      new Vue({
          template:``,
          el:'#root',
          components:{App}
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • index.html

      DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>单文件组件练习title>
      head>
      <body>
          <div id="root">div>
          <script src="../../js/vue.js">script>
          <script src="./main.js">script>
      body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

    3 vue脚手架

    3.1 初始化脚手架

    3.1.1 基本介绍

    vue-cli(vue脚手架)是vue官方提供的标准化开发平台

    目前最新 的版本是5.x

    3.1.2 使用步骤

    • 配置淘宝镜像cnpm (这一步不是必须的,主要为了安装扩展包时候加速的)

      npm config set register http://registry.npm.taobao.org
      
      • 1
    • 全局安装@vue/cli

      npm install -g @vue/cli
      
      • 1
    • 切换到需要创建项目的目录,创建一个空的vue项目

      vue create xxx // xxx是项目名称
      
      • 1
    • 选择使用的vue版本

      选择vue2,等待下载安装依赖包,这里需要联网

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAbFV7wu-1663494649206)(D:\markdown\Vue速成手册.assets\image-20220722150357812.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ab37CKoo-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220722150416187.png)]

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-slE6bzIt-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220722150523086.png)]

    ​ 表示成功创建了项目。

    • 启动项目

      npm run serve   // 注意这里是serve 不是server
      
      
      • 1
      • 2
    • 打包项目

      npm run build  // 用于生产环境的打包
      
      • 1
    • 停止运行的测试服务器

      Ctrl+C
      
      • 1

    vue脚手架隐藏了所有webpack相关的配置,若想查看具体的webpack配置,请执行vue inspect > output.js

    output.js只能用于查看配置项,在output.js中修改配置并不能改变vue的配置项

    3.2 脚手架项目文件结构

    .文件目录
    ├── node_modules 
    ├── public
    │   ├── favicon.ico: 页签图标
    │   └── index.html: 主页面
    ├── src
    │   ├── assets: 存放静态资源
    │   │   └── logo.png
    │   │── component: 存放组件
    │   │   └── HelloWorld.vue
    │   │── App.vue: 汇总所有组件
    │   └── main.js: 入口文件
    ├── .gitignore: git版本管制忽略的配置
    ├── babel.config.js: babel的配置文件
    ├── package.json: 应用包配置文件 
    ├── README.md: 应用描述文件
    └── package-lock.json: 包版本控制文件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.3 修改配置项

    使用vue.config.js 可以对脚手架进行个性化定制

    module.exports = {
      pages: {
        index: {
          entry: 'src/index/main.js' // 入口
        }
      },
      lintOnSave: false	// 关闭语法检查
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    配置参考链接:

    https://cli.vuejs.org/zh/config/#devserver-proxy

    3.4 main.js 文件解读

    import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.4.1 不同版本的vue

    选择runtime版本的vue的目的是为了减少生产环境的空间,提高效率

    默认情况下,vue脚手架使用的vue是runtime版本

    • vue.js与vue.runtime.xxx.js的区别

      vue.js是完整的Vue,包含核心功能+模板解析器

      vue.runtime.xxx.js,只包含核心功能,没有模板解析器

      vue.runtime.xxx.js中没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去执行具体内容

    3.4.2 render函数

    // render函数的完整形式: 
    render(createElement){
        return createElement(App)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4 脚手架内组件通讯

    4.1 ref属性

    ref用来给元素或子组件注册引用信息,类似于id

    将ref应用在html标签上获取的是真实的DOM元素;应用在组件标签上获取的是组件实例对象vc

    • 设置ref标识

      
      <h1 ref="h1"> 组件间通讯 h1>
      
      <School ref="school">School>
      
      • 1
      • 2
      • 3
      • 4
    • 获取ref

      this.$refs.xxx 获取ref
      
      this.$refs  返回一个对象
      
      • 1
      • 2
      • 3
    • App.vue

      
      
      
      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
    • School.vue

      
      
      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23

    4.2 props属性

    props 让组件接收外部传来的数据

    • 传递数据

      <School name='清华大学' :age="122">school> 
      
      
      • 1
      • 2

      注意:这里的:age 是 v-bind:age的缩写,通过v-bind,122是一个整数类型

    • 接收数据

      • 方式一:

        props: ['name', 'age']
        
        • 1
      • 方式二(限制接收到变量的类型):

        props: {
        	name: String,
        	age: Number
        }
        
        • 1
        • 2
        • 3
        • 4
      • 方式三 (限制类型,限制必要性,设定默认值)

        props:{
        	name: {
        		type: String, // 限制类型
        		required: true, // 必须传递
        		default: 'kobe' // 默认值
        	}
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7

    注意:

    props是只读的,vue底层会监视props属性中的值,如果对其进行修改,不会报错,但是会提示,如果需要修改props中的值,请将props复制到data中进行修改。

    • demo

      • 普通接收

        • App.vue
        <template>
          <div>
            <div class="first-menu">
              <h1 ref="h1"> 组件间通讯 </h1>
              <h3>props属性</h3>
              <hr>
            </div>
            <div class="content">
              <School ref="school" name="清华大学" addr="北京"></School>
              <School ref="school" name="武汉大学" addr="武汉"></School>
              <School ref="school" name="厦门大学" addr="厦门"></School>
            </div>
          </div>
        </template>
        
        <script>
        
        import School from "@/components/School";
        
        export default {
          name: 'App',
          components: {
            School
          },
        }
        </script>
        
        <style>
        .active {
          background-color: cornflowerblue;
        }
        
        .content {
          position: absolute;
          left: 200px;
        }
        </style>
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • School.vue

          
          
          
          
          
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
          • 14
          • 15
          • 16
          • 17
          • 18
          • 19
          • 20
          • 21
          • 22
      • 限制变量类型接收

        <template>
          <div>
            <h4 ref="info">学校信息</h4>
            <p>学校名称: {{ name }}</p>
            <p>学校地址:{{ addr }} </p>
            <hr>
          </div>
        </template>
        
        <script>
        export default {
          name: "School",
          data() {
            return {}
          },
          props: {
            name: String,
            addr: Number // 如果传递的不是数字型,报下方错误
          }
        }
        </script>
        
        <style scoped>
        
        </style>
        
        // Vue warn]: Invalid prop: type check failed for prop "addr". Expected Number with value NaN, got String with value "北京".
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
      • 限制类型、必要性、默认值

        <template>
          <div>
            <h4 ref="info">学校信息</h4>
            <p>学校名称: {{ name }}</p>
            <p>学校地址:{{ addr }} </p>
            <hr>
          </div>
        </template>
        
        <script>
        export default {
          name: "School",
          data() {
            return {}
          },
          props: {
            name: {
              type: String,
              required: true,
              default: '家里蹲大学'
            },
            addr: {
              type: String,
              required: true,
              default: 'home'
            }
          }
        }
        </script>
        
        <style scoped>
        
        </style>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33

    4.3 mixin 属性

    可以把多个组件共用的配置提取成一个混入mixin对象.

    • 定义mixin

      const xxx = {
      	// 公用数据
      	data(){....},
      	// 公用方法
      	methods: {},
      	// 钩子函数
      	created() {}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 使用mixin

      • 全局使用混入

        Vue.mixin(xxx)
        
        
        • 1
        • 2
      • 局部使用混入

        mixins: ['xxx', ]
        
        
        • 1
        • 2
    • demo

      • src/mixin/index.js

        const mixin = {
            data() {
                return {
                    'login': 'xxxx'
                }
            },
            methods: {
                Login() {
                    alert('登录视图')
                },
                Logout() {
                    alert('登出视图')
                }
            },
            created() {
                alert('mixin 创建组件钩子函数')
            }
        }
        
        export default mixin
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
      • src/App.vue (局部导入)

        
        
        
        
        
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
      • src/main.js(全局导入)

        import Vue from 'vue'
        import App from './App.vue'
        
        // 引入ElementUI
        import ElementUI from 'element-ui'
        // 引入ElementUI 全部样式
        import 'element-ui/lib/theme-chalk/index.css'
        
        Vue.use(ElementUI) // 全局使用ElementUI
        
        Vue.config.productionTip = false
        
        import mixin from '@/mixins'
        
        Vue.mixin(mixin)  // 全局导入
        
        new Vue({
            render: h => h(App),
        
        }).$mount('#app')
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21

    4.4 plugin 属性

    用于提升、扩展Vue的功能

    • 本质

      包含install方法的一个对象,install的第一个参数是Vue,第二个的参数是插件使用者传递的数据

    • 使用插件

      Vue.use()

    • demo

      • src/plugin/index.js

        export default {
         install(Vue, x,y,z){
         	 console.log(x,y,z)
             // 全局过滤器
             Vue.filter('myslice', function(value){return value.slice(0,4)})
             // 定义全局指令
             Vue.directive('fbind', {
                 // 指令与元素成功绑定时
                 bind(element, binding) {element.value = binding.value}
             },
                 // 指令所在元素被插入页面时
                 inserted(element, binding){element.focus()}
            	 // 指令所在的模板被重新解析时
            	 update(element, binding){element.value = binding.value}
                          )
         		}
             // 定义混入
             Vue.mixin({
                 data(){
                     return {
                         x: 100, y:200
                     }
                 }
             })
        	// 给Vue原型上添加一个方法(vm和vc可以用)
        	Vue.prototype.hello = ()=>{alert('hello plugins!')}
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
      • src/main.js

        Vue.use(Vue, 1,2,3) // 应用插件
        
        • 1

    4.5 scoped 属性

    
    
    
    ## 4.6 自定义事件
    
    父组件传递数据到子组件,使用props
    
    ==**自定义事件是从子组件传递数据到父组件**==
    
    子组件想要给父组件传递数据,要在父组件中给子组件定义自定义事件,事件回调在父组件中
    
    - 语法
    
      - 父组件
    
        ```vue
        
        
        
        
        ```
    
      - 子组件
    
        ```vue
        
        
        ```
    
        ```js
        this.$emit('customEvent') // 解绑一个自定义事件
        this.$emit(['event1', 'event2']) // 解绑多个自定义事件
        this.$destroy() // 销毁子组件,绑定其身上的自定义事件随着全部失效 
        ```
    
      - 父组件 方式2
    
        ```vue
        
        
        
        ```
    
      - 父组件无论使用方式1还是方式2,子组件的使用方式均相同。
    
    - 组件绑定原生事件
    
      在原生事件后面加上==**.native**==  否则原生事件也会被当做是自定义事件。
    
      ```js
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    4.7 全局事件总线

    4.7.1 定义

    一种可以在任意组件之间通信的方式,不限于父子组件之间,本质上就是一个对象

    • 所有的组件都必须能够看到这个对象
    • 这个对象必须能够使用$on、$emit、$off、方法去绑定、触发和解绑事件

    4.7.2 使用步骤

    • 定义全局事件总线

      new Vue({
          ...
          beforeCreate() {
          	Vue.prototype.$bus = this  // 安装全局事件总线, $bus就是当前的vm
      	}
          ...
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • 使用全局事件总线

      • 接收数据

        接收数据的组件,使用$bus.$on定义自定义数据,回调函数留在接收数据的组件中.

      • 提供数据

        提供数据的组件使用$bus.$emit()触发自定义事件

    • 解绑当前组件中用到的所有事件,beforeDestroy()

    • Demo

      • 接收数据的组件

        
        
        
        
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43
        • 44
        • 45
        • 46
        • 47
        • 48
        • 49
        • 50
        • 51
        • 52
        • 53
        • 54
        • 55
        • 56
        • 57
        • 58

        发送数据的组件

        
        
        
        
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28

    4.7.3 小结

    全局事件总线相比较自定义事件总线更加灵活。

    4.8 发布与订阅

    用的较少,先不展开,后面有时间在搞。

    5 vuex

    5.1 搭建vuex环境

    • 安装

      npm i vuex@3 vuex目前最新版本是4版本,4版本必须使用vue3,如果使用vue2版本,必须安装vuex3,否则安装会报错

    • 配置

      在src文件下创建store目录,在目录内创建index.js

      看图说话:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IludkSgi-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220802231636436.png)]

      // 导入Vue
      import Vue from 'vue'
      // 导入Vuex
      import Vuex from 'vuex'
      // 注册插件
      Vue.use(Vuex)
      
      const actions = { // 
          xxx(context, value) {
              context.commit('ADD', value)
          },
      }
      
      const mutations = {
          ADD(state, value) {
              state.sum += value
          },
      }
      
      const state = {
          sum: 10
      }
      
      export default new Vuex.Store({
          actions,
          mutations,
          state
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28

    5.2 getter

    5.3 模块化

    6 vue-router

    6.1 安装

    当前最新的vue-router版本是V4.x,V4.x版本的vue-router适用于vue3,如果使用vue2版本,请使用vue-router3.x版本

    npm i vue-router@3 
    cnpm i vue-router@3 # 使用淘宝镜像安装,可以加速
    
    • 1
    • 2

    6.2 配置

    • src/router/index.js

      import Vue from 'vue'
      import VueRouter from 'vue-router'
      import About from '../components/About'
      import Home from '../components/Home'
      
      Vue.use(VueRouter)
      
      export default new VueRouter({
          routes: [
              {
                  path: '/about',
                  component: About
              },
              {
                  path: '/home',
                  component: Home
              }
          ]
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    • src/main.js

      import Vue from 'vue'
      import App from './App.vue'
      import router from './router'
      
      Vue.config.productionTip = false
      
      new Vue({
        render: h => h(App),
        router
      }).$mount('#app')
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    • src/components/App.vue

      
      
      
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
    • src/components/About.vue

    • src/components/Home.vue

    6.3 路由传参query

    假设有一个图书管理系统,首页显示所有图书的列表,当点击每本图书后,显示图书的详细视图,点击不同的图书显示不同的详细视图,类似这种需求就需要给路由传参。

    vue-router中路由传参有两种写法,分别是字符串写法和对象写法。

    src/router/index.js

    import Vue from "vue"
    import VueRouter from 'vue-router'
    
    import Detail from "@/components/Detail";
    
    Vue.use(VueRouter)
    
    export default new VueRouter({
        routes: [
            {
                path: '/books',
                component: Detail
            }
        ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    src/App.vue

    
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    src/components/Detail.vue

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 路由传参方式1:

      <router-link :to="`/books?id=${id}&name=${name}&publish=${publish}`">跳转</router-link>
      
      • 1

      在组件中使用$route.query.name 等获取路由中传递的参数

    • 路由传参方式2:

      			<router-link :to="{
                    path: '/books',
                    query: {
                      id: book.id,
                      name: book.name,
                      publish: book.publish
                    }
                  }">
                    {{ book.name }}
                  </router-link>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

      在组件中使用$route.query.name 等获取路由中传递的参数

    6.4 命令路由

    为了简化多级路由的写法,可以在定义路由时添加一个name属性。

    src/router/index.js

    routes: [
            {
                name: 'detail',
                path: '/books',
                component: Detail
            }
        ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    src/App.vue

    • 不需要传参,to属性使用字符串拼接写法和对象写法都可以

      字符串写法

      <router-link :to="{name: 'detail'}">跳转</router-link>
      
      • 1

      对象写法

      <router-link :to="{
      	name:'detail'}">
      <router-link>
      
      • 1
      • 2
      • 3
    • 需要传参,to属性必须使用对象写法

      <router-link :to="{
      	name:'detail',
      	query: {
      		id: '01',
      		name: '水浒传',
      		publish: '中国出版社'
      	}
      
      }">
      <router-link>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10

    6.5 路由传参params

    query传参是在跳转时传递参数,类似get请求传参,将参数通过?链接到url后面,通过&符号链接多个key-value.

    http://127.0.0.1:8000/books?id=1&name=水浒传

    id和name就会传递给/books路由对应组件的$router.query中。

    params在定义路由的时候就要确定要传递的参数,在path中使用占位符声明接收params参数,如果使用params传参,to的对象写法不能使用path属性,必须使用name属性。

    src/router/index.js

    import Vue from "vue"
    import VueRouter from 'vue-router'
    
    import Detail from "@/components/Detail";
    
    Vue.use(VueRouter)
    
    export default new VueRouter({
        routes: [
            {
                name: 'detail',
                path: '/books/:id/:name/:publish',  // 使用:占位符对需要传递的参数占位
                component: Detail
            }
        ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    src/App.vue

    '''
    
                                {{ book.name }}
                              
    '''
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    再次重申,如果to使用对象写法,必须使用命名路由,不能使用path

    '''
    {{ book.name }}
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    src/component/Detail.vue

    使用$route.params.xxx接收路由中的params参数

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    6.6 路由props属性

    props可以让路由更方便接收到参数:

    {
    	name:'detail',
    	path:'books/:id/:name/:publish',
    	component:Detail,
    
    	//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
    	// props:{a:900}
    
    	//第二种写法:props值为布尔值,为true时,则把路由收到的所有params参数通过props传给Detail组件
    	// props:true
    	
    	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
    	props($route){
    		return {
    			id: $route.query.id,
    			title: $route.query.title
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    src/route/index.js

    import Vue from "vue"
    import VueRouter from 'vue-router'
    
    import Detail from "@/components/Detail";
    
    Vue.use(VueRouter)
    
    export default new VueRouter({
        routes: [
            {
                name: 'detail',
                path: '/books/:id/:name/:publish',
                component: Detail,
                // 写法1:对象写法
                // props: {    
                //     hello: 'world'
                // }
                // 写法2: 布尔值
                //props: true
                // 写法3: 函数写法
                props($route){
                    return {
                        xixi:$route.params.id,
                        haha:$route.params.name,
                        xxoo: $route.params.publish
                    }
                }
            }
        ]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    /src/components/Detail.vue

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.7 编程式路由导航

    6.7.1 浏览器缓存

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JXxXgPPA-1663494649207)(D:\markdown\Vue速成手册.assets\image-20220917172112078.png)]

    在浏览器左上角一般都会有两个箭头,分别表示“向前"和"向后".

    浏览器的路由缓存类似于一个栈,有两种存储地址的方式:

    • replace 方式:

      <router-link :replace=true>Name</router-link>
      // 简写方式
      <router-link replace>Name</router-link>
      
      • 1
      • 2
      • 3
    • push方式(默认):

      
      
      • 1

    6.7.2 编程式路由组件(不使用router-link实现路由跳转)

    不借助实现路由跳转,让路由跳转更加灵活

    this.$router.push({})
    this.$router.replace({})
    this.$router.forward()  // 前进
    this.$router.back()  // 后退
    this.$router.go(n)   // 可前进也可后退,正数为前进,负数为后退
    
    • 1
    • 2
    • 3
    • 4
    • 5

    push和replace里面的参数和to相同:

    this.$router.push({
    	name: 'router name'
    })
    
    • 1
    • 2
    • 3
    • Test.vue
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • Xiangxi.vue
    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.8 缓存路由组件

    默认情况下:路由组件被切换后,会被vue销毁,所以在该组件中的数据都将被清除。

    keep-alive 标签可以将组件缓存,不被销毁,所以在路由切换后能够保存组件中的数据。

    • 缓存一个组件

      include 属性中填写组件名

      <keep-alive include="Python">
              <router-view></router-view>
            </keep-alive>
      
      • 1
      • 2
      • 3
    • 缓存多个组件

      include属性中填写组件列表

      注意:缓存一个组件的时候,include前面没有冒号:,缓存多个组件的时候,include前面有冒号:

      <keep-alive :include="['Python', 'Java']">
              <router-view></router-view>
            </keep-alive>
      
      • 1
      • 2
      • 3
    • 缓存所有组件 不写include属性就代表缓存所有

      
      	
      
      
      • 1
      • 2
      • 3

    6.9 路由相关的钩子函数

    • activated

      路由组件被激活时触发

    • deactivated

      路由组件失活时触发

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    6.10 路由守卫

    对路由权限进行控制

    路由配置中通过:meta配置源信息

    6.10.1 全局守卫

    对所有组件都起作用

    • 全局前置守卫:初始化时,每次路由切换前执行

      router.beforeEach((to, from, next) => {
          if (to.meta.requireAuth) {
              let c = localStorage.getItem('class')
              if (c === 'v') {
                  next()
              } else {
                  alert('无权访问')
                  next(false)
              }
          } else {
              next()
          }
      })
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dYvPKB9A-1663494649208)(D:\markdown\Vue速成手册.assets\image-20220918093757914.png)]

    • 全局后置守卫:初始化时,每次路由切换后执行

      router.afterEach((to, from)=>{
          document.title = to.meta.title
      })
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cyq5sdyx-1663494649208)(D:\markdown\Vue速成手册.assets\image-20220918093838110.png)]

    • 小结

      to,from,next三个参数都是必要的
      to:即将要进入的目标 路由对象
      from:当前导航正要离开的路由
      next:一定要调用该方法来处理这个钩子,如果不写next()或者next(false),页面路由不会跳转,也就是页面被阻止在当前页面了
      to,from是一个对象,就是 routes[] 数组里面配置的某个具体的路由对象,
      比如:to.path, to,name, to.meta 或 from.path, from.name, from.meta 【path,name,meta】这些字段都是自己在路由里面定义的字段,这样就可以开始写逻辑了。
      next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
      
      next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
      
      next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
      
      next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

    6.10.2 独享守卫

    对某个组件起作用,你可以在路由配置上直接定义 beforeEnter 守卫:

    参数与全局前置守卫相同:

    {
            path: '/class',
            name: 'class',
            meta: {
                requireAuth: true,
                title: 'Class'
    
            },
            component: Class,
            children: [
                {
                    path: 'python',
                    name: 'python',
                    component: Python,
                    beforeEnter: (to, from, next)=>{
                        if (localStorage.getItem('class') === 'v1'){
                            next()
                        }else{
                            alert('无权访问')
                            next(false)
                        }
                    }
                },
            ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.10.3 组件内守卫

    • 通过路由匹配后,进入路由组件时守卫

      beforeRouteEnter((to, from, next)=>{})
      
      • 1
    • 离开路由组件时守卫

      beforeRouteLeave((to, from, next)=>{})
      
      • 1

    6.10.4 路由的两种模式

    • hash

      地址中有#号
      地址中#号后面的值不会出现在http请求中
      兼容性好
      不美观
      app检验严格的情况会被标记为不合法
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • history

      地址干净、美观
      兼容性比hash差
      可能会出现404报错,因为路径中的数据会被发送到后端
      
      • 1
      • 2
      • 3
    • 设置模式

      const router = new VueRouter({
          mode: 'history' or 'hash'
      })
      
      • 1
      • 2
      • 3

    7 vue ui组件库

    1 安装element-ui

    cnpm i element-ui -S
    
    • 1

    2 全局配置

    src/main.js

    import Vue from 'vue'
    import App from './App.vue'
    // 引入ElementUI  
    import ElementUI from 'element-ui'
    // 引入ElementUI 全部样式
    import 'element-ui/lib/theme-chalk/index.css'
    
    Vue.use(ElementUI) // 全局使用ElementUI
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    src/App.vue

    
    
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3 部分配置

    1 安装babel-plugin-component

    npm i babel-plugin-component -D
    
    • 1

    2 修改babel-config-js

    module.exports = {
      presets: [
        '@vue/cli-plugin-babel/preset',
        ["@babel/preset-env", { "modules": false }]
      ],
      plugins: [
        [
          "component",
          {        
            "libraryName": "element-ui",
            "styleLibraryName": "theme-chalk"
          }
        ]
      ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    src/main.js

    import Vue from 'vue'
    import App from './App.vue'
    import { Button,Row } from 'element-ui'	// 按需引入
    
    Vue.config.productionTip = false
    
    Vue.component(Button.name, Button);
    Vue.component(Row.name, Row);
    /* 或写为
     * Vue.use(Button)
     * Vue.use(Row)
     */
    
    new Vue({
        el:"#app",
        render: h => h(App),
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    一般如果对性能要求不是太苛刻的话都会选择全局配置

    8 LocalStorage 和 SessionStorage

    8.1 LocalStorage(本地存储)

    • setItem

      localStorage.setItem('k1', 'v1')
      
      • 1
    • getItem

      localStorage.getItem('k1')
      'v1'
      
      • 1
      • 2
    • length 属性

      localStorage.length
      1
      
      • 1
      • 2
    • getItem

      localStorage.getItem('k2')
      'v2'
      
      • 1
      • 2
    • clear 清楚所有存储

      localStorage.clear()
      
      • 1
    • localStorage.removeItem

      localStorage.removeItem('k1')
      
      • 1

    8.2 SessionStorage(会话存储)

    • API与localStorage相同

      - setItem(key, value)
      - getItem(key)
      - removeItem(key)
      - length 
      - clear() 清空所有的会话存储
      
      • 1
      • 2
      • 3
      • 4
      • 5

    常见问题总结:

    1 Component name “Class” should always be multi-word vue/multi-word-component-names

    • 解决方式1:

      在vue.config.js中添加关闭语言检查功能

      const {defineConfig} = require('@vue/cli-service')
      module.exports = defineConfig({
          transpileDependencies: true,
          lintOnSave: false /*关闭语法检查*/
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
    • 解决方式2:

      按照要求修改组件名

    2 路由文件与main文件分模块时报如下错误:Error in beforeCreate hook: “TypeError: this._router.init is not a function”

    问题原因: 导出和导入模块的方式不对

    正确的处理方式:

    
    格式一 变量形式 --暴露
    
    export default {
    
    router
    
    }
    
    --接收
    
    import {router} from './router'
    
    
    
    格式二 直接暴露
    
    
     export default router
    
    接收
    
    import router from './router'
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    安卓实训作孽之Linux命令手册
    静态/动态代理模式
    mybatis各阶段的详解
    C【程序环境和预处理】
    第十四章 手动创建 REST 服务(二)
    Linux学习笔记(二)
    HTML网页设计制作——响应式网页影视动漫资讯bootstrap网页(9页)
    【模板】MST最小生成树(Prim算法、Krustra算法)
    设计师必备,6个PNG素材网站
    动态内存精讲
  • 原文地址:https://blog.csdn.net/kobe_okok/article/details/126920652