Vue 2.0 知识点总结

Vue 2.0 知识点总结


Vue 2.0 知识点总结

1. vue 简介

1.1 框架的概念

  • 概念:框架指的就是程序员必须遵守的规则或约束。
  • 例如:
    1. 想要驾驶汽车,就必须遵守交通规则;
    2. 想要使用 vue 开发前端项目,就必须掌握 vue 的使用规则

1.2 Vue的概念

  • vue 的官方文档(使用说明书):https://cn.vuejs.org/v2/guide/

  • 官方给出的概念:vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架

  • vue 不强求程序员一次性接受并使用它的全部功能特性。

image.png

1.3 vue 的特性

  • vue 框架的特性,主要体现在如下两方面:
    1. 数据驱动视图
    2. 双向数据绑定
数据驱动视图

在使用了 vue 的页面中,data 数据的变化,会导致页面结构的重新渲染。示意图如下:

image.png

双向数据绑定
  1. data 数据的变化,会导致页面的重新渲染
  2. 表单数据的变化,会被自动更新到 data 数据中

image.png

MVVM
  • MVVM 是 vue 实现数据驱动视图和双向数据绑定的核心原理
  • MVVM 指的是 ModelViewViewModel
  • 它把每个 HTML 页面都拆分成了这三个部分,如图所示:

image.png

MVVM 的工作原理
  • ViewModel 作为 MVVM 的核心,是它把当前页面的数据源(Model)和页面的结构(View)连接在了一起。

image.png

  • 数据源发生变化时,会被 ViewModel 监听到,VM 会根据最新的数据源自动更新页面的结构
  • 表单元素的值发生变化时,也会被 VM 监听到,VM 会把变化过后最新的值自动同步到 Model 数据源中

2. vue 的基本使用

2.1 初步导入和配置

  • 步骤1:导入 Vue 的 JS 文件,window 全局挂载名为 Vue 的构造函数
  • 步骤2:new 构造函数,创建 Vue 的实例对象,用 vm 来表示
  • 步骤3:通过 el 选项,指定当前的 Vue 实例要控制页面上哪个区域的渲染
  • 步骤4:创建需要被 Vue 实例控制的 DOM 区域。

image.png
注意:选择器一定要和 el 选项的值匹配

2.2 定义和使用数据

  • vue 提供了 data 选项,专门用来定义数据,供页面渲染时使用。

image.png

3. vue 的调试工具

3.1 安装 vue-devtools 调试工具

  • vue 官方提供的 vue-devtools 调试工具,能够方便开发者对 vue 项目进行调试与开发。
  1. Chrome 浏览器在线安装 vue-devtools

  2. FireFox 浏览器在线安装 vue-devtools

3.2 配置 Chrome 浏览器中的 vue-devtools

  • 点击 Chrome 浏览器右上角的 按钮,选择更多工具 -> 扩展程序 -> Vue.js devtools 详细信息,并勾选如下的两个选项:

image.png

3.3 使用 vue-devtools 调试 vue 页面

  • 在浏览器中访问一个使用了 vue 的页面,打开浏览器的开发者工具,切换到 Vue 面板,即可使用 vue-devtools调试当前的页面。

image.png

4. vue 的指令

4.1 指令的概念

  • 概念:指令(Directives)是 vue 为开发者提供的一套特殊语法。
  • 为啥要学:提高程序员渲染 DOM 的效率。
  • vue 中的指令按照不同的用途可以分为如下 6 大类
    1. 内容渲染指令
    2. 属性绑定指令
    3. 事件绑定指令
    4. 双向绑定指令
    5. 条件渲染指令
    6. 列表渲染指令
  • 注意:指令是 vue 开发中最基础、最常用、最简单的知识点。

4.2 六大类指令

1. 内容渲染指令
  • 内容渲染指令用来辅助开发者渲染 DOM 元素的文本内容。
  • 常用的内容渲染指令有如下 3 个:
    1. v-text 填充纯文本
    • 不解析标签
    • 相比插值表达式更加简洁
    1. 插值表达式
    • 表达式:{{}}
    • 优点:大家都遵循同样的规则写代码,代码可读性明显提高了,方便后期的维护。
    • 缺点:没有专门提供事件机制。
    1. v-html 填充HTML片段
    • v-text 指令和插值表达式只能渲染纯文本内容。如果要把包含 HTML 标签的字符串渲染为页面的 HTML 元素,则需要用到 v-html 这个指令
    1. v-pre 填充原始信息
    <!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>Document</title>
    </head>
    
    <body>
      <div id="app">
        <p>------------ v-text ---------------</p>
        <!-- 注意:v-text 很少用,因为它会覆盖元素内默认的内容 -->
        <p v-text="username">名字是:</p>
        <p v-text="gender">性别:</p>
    
        <p>------------ { { } } ---------------</p>
        <!-- 插值表达式 -->
        <!-- 表达式的概念:可以求值的式子,叫做表达式 -->
        <p>名字是:{{ username }}</p>
        <p>性别是:{{ gender }}</p>
        <p>{{ username + '~~~' }}</p>
        <p>{{ username + gender }}</p>
        <p>{{ 123 }}</p>
        <p>{{ true }}</p>
        <p>{{ 1>3 ? '成立' : '不成立' }}</p>
        <p>{{ username.length }}</p>
        <!-- 语句不能写到插值表达式中,里面只能写“表达式” -->
        <!-- <p>{{ let a = 10 }}</p> -->
        <p>{{ username.split('').reverse().join('') }}</p>
    
        <p>--------------- v-html ---------------</p>
        <div v-text="info"></div>
        <div>{{info}}</div>
        <div v-html="info"></div>
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          // 声明数据
          data: {
            username: '汤哥1234',
            gender: '男',
            info: '<h3 style="color:red;">这是一个h3标签</h3>'
          }
        })
      </script>
    </body>
    
    </html>
    
2. 属性绑定指令
  • 语法:v-bind:属性名=“表达式”
  • 简写::属性名=“表达式”
  • 作用:标签的属性与vue表达式动态绑定
  • 注意:在实际开发中,v-bind: 指令特别常用,因此,vue 提供了简化的写法 :
    <!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>Document</title>
    </head>
    
    <body>
      <div id="app">
        <!-- v-bind: 是属性绑定指令,专门为元素属性动态绑定属性值 -->
        <!-- v-bind:属性名="表达式" -->
        <!-- 注意:在实际开发中,v-bind: 指令特别常用,因此,vue 提供了简化的写法 : -->
        <input type="text" :placeholder="info">
        <img :src="url" alt="">
        <h3 :title="txt + '~~~~'">xxxxxxxxxxx</h3>
        <input :type="password" placeholder="v-bind: 是属性绑定指令">
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          data: {
            info: 'abcdefg',
            // 图片的 url 地址
            url: 'https://img0.baidu.com/it/u=3280618160,1318135601&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500',
            txt: '这是h3的标题',
            password: 'password'
          }
        })
      </script>
    </body>
    
    </html>
    
3. 事件绑定指令
  • 语法:

    1. v-on:事件名="methods中的函数(实参)"
    2. v-on:事件名="methods中的函数"
  • 简写: @事件名="methods中的函数"

  • 作用:给DOM元素绑定事件

  • 事件对象

    1. 无参数,直接用形参接收
    2. 有参数,手动传入 $event 对象
  • $event:$event 是 vue 提供的特殊变量,用来表示原生的事件参数对象 event。$event 可以解决事件参数对象event被覆盖的问题。

    <!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>Document</title>
    </head>
    
    <body>
      <div id="app">
        <h3>count是:{{ count }}</h3>
        <!-- 当绑定事件的时候,用小括号传参了 -->
        <!-- 则传递的参数,会把默认的事件对象 event 给覆盖掉 -->
        <!-- $event 是 vue 内置的特殊变量,它就是事件对象 event -->
        <button @click="add(2, $event)">+N</button>
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          data: {
            count: 0
          },
          methods: {
            // 绑定事件,必然会有事件对象 event
            add (n, e) {
              console.log(n, e.target);
              // e.target 是事件的触发源
              // 记住:e.target 是原生的 DOM 对象
              e.target.style.backgroundColor = 'red'
    
              this.count += n
    
              // 在 add 函数中,调用 show 函数
              this.show()
            },
            show () {
              console.log('触发了 methods 中的 show 函数')
            }
          },
        })
      </script>
    </body>
    
    </html>
    
  • 事件修饰符

    • 语法:@事件名.修饰符名
    • 常用的 5 个事件修饰符如下:
      image.png
    <!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>Document</title>
      <style>
        .outer {
          padding: 100px 50px;
          background-color: orange;
        }
    
        .inner {
          padding: 50px;
          background-color: cyan;
        }
      </style>
    </head>
    
    <body>
      <div id="app">
        <!-- @事件名.prevent="处理函数" -->
        <a href="https://juejin.cn/editor/drafts/7075957234605244447" @click.prevent="show">去掘金网站</a>
    
        <div class="outer" @click="handler2">
          <!-- @事件名.stop="处理函数" -->
          <div class="inner" @click.stop="handler1">内部的 div</div>
        </div>
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          methods: {
            show () {
              console.log('点击了 a 链接')
            },
            handler1 () {
              console.log('点击了内部的盒子')
            },
            handler2 () {
              console.log('点击了外部的盒子')
            }
          },
        })
      </script>
    </body>
    
    </html>
    
  • 按键修饰符

    • 在监听键盘事件时,我们经常需要判断详细的按键。此时,可以为键盘相关的事件添加按键修饰符
    • 回车键触发 @keyup.enter
    • 取消键触发 @keyup.esc
<!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>Document</title>
</head>

<body>
  <div id="app">
    <!-- .enter 能保证,只有摁下的是 enter 键的时候,才触发后面的函数 -->
    <!-- 摁下 esc 清空文本框 -->
    <!-- 1. 绑定 keyup 事件,并监听 esc 按键 -->
    <!-- 2. 声明事件处理函数 -->
    <!-- 3. 通过 e.target.value = '' 来清空文本框的值 -->
    <input type="text" @keyup.enter="submit" @keyup.esc="clear">
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script>
    const vm = new Vue({
      el: '#app',
      methods: {
        submit (e) {
          console.log('触发了 submit 函数')
          console.log(e.target.value)
        },
        clear (e) {
          console.log('触发了 esc 函数')
          e.target.value = ''
        }
      },
    })
  </script>
</body>

</html>
4. 双向绑定指令
  • vue 提供了 v-model 双向数据绑定指令,用来辅助开发者在不操作 DOM 的前提下,快速获取表单的数据

  • 语法: v-model="vue数据变量"

  • 作用:把标签的 value 属性 与 vue变量 双向绑定

  • v-model 指令的修饰符

    • 为了方便对用户输入的内容进行处理,vue 为 v-model 指令提供了 3 个修饰符,分别是:

    image.png

    <!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>Document</title>
    </head>
    
    <body>
      <div id="app">
        <h3>count是:{{count}}</h3>
        <button @click="count += 1">+1</button>
    
        <hr>
    
        <!-- 分析思路: -->
        <!-- 1. 为 input 绑定 input 事件 -->
        <!-- 2. 在处理函数中,通过 e.target.value 获取到变化过后的新值 -->
        <!-- 3. 把新值,调用 parseInt 转换为 数值 -->
        <!-- 4. 把转换得到的数值,赋值给 this.count -->
        <!-- 注意: change 在文本框失去焦点时候触发;input 在每次值变化的时候触发 -->
        <input type="text" :value="count" @input="getValue">
    
        <hr>
    
        <!-- v-model 是双向数据绑定指令,它有两个作用: -->
        <!-- 1. data 数据的变化,会被自动渲染到当前的元素中 -->
        <!-- 2. 当前元素值的变化,会被自动更新到 data 中 -->
        <input type="text" v-model.number="count">
    
        <hr>
        <!-- v-model 指令,可以让当前元素的值,和 data 中的数据,进行双向数据绑定 -->
        <!-- .lazy 表示,文本框触发 change 事件的时候,才会把数据更新到 data -->
        <input type="text" v-model.lazy.trim="msg">
    
        <hr>
        <!-- 切记:v-model 指令,只能结合表单元素一起使用;不能结合普通标签一起使用 -->
        <!-- input  type=text/password/email/radio/checkbox -->
        <!-- select -->
        <!-- textarea -->
        <!-- <div v-model="msg"></div> -->
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        // 3. vm 实例就是 ViewModel
        const vm = new Vue({
          // 2. el 所指定的区域,就是 View 视图
          el: '#app',
          // 1. Model 数据源
          data: {
            count: 0,
            msg: 'abc'
          },
          methods: {
            getValue(e) {
              // console.log(typeof e.target.value)
              this.count = parseInt(e.target.value)
            }
          },
        })
      </script>
    </body>
    
    </html>
    
5. 条件渲染指令
  • 条件渲染指令用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:

    • v-if
    • v-show
  • 语法:

    • v-show="vue变量"
    • v-if="vue变量"
  • 原理:

    • v-show 用的display:none隐藏 (频繁切换使用)
    • v-if(不频繁): 动态创建和移除元素插入或移除节点
  • v-if 和 v-show 的区别

    1. 实现原理不同:
    • v-if 指令会动态地创建或移除 DOM 元素,从而控制元素在页面上的显示与隐藏;
    • v-show 指令会动态为元素添加或移除 style=“display: none;” 样式,从而控制元素的显示与隐藏;
    1. 性能消耗不同:
    • v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
    • 如果需要非常频繁地切换,则使用 v-show 较好
    • 如果在运行时条件很少改变,则使用 v-if 较好
    <!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>Document</title>
    </head>
    
    <body>
      <div id="app">
        <button @click="flag = !flag">Toggle</button>
        <p v-if="!flag">这是被 v-if 控制的元素</p>
        <p v-show="flag">这是被 v-show 控制的元素</p>
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          data: {
            // 如果 falg 为 true,则展示被控制的元素
            // 如果 falg 为 false,则隐藏被控制的元素
            flag: false
          }
        })
      </script>
    </body>
    
    </html>
    
    
  • v-else

    • v-if 可以单独使用,或配合 v-else 指令一起使用:
    • 注意:v-else 指令必须配合 v-if 指令一起使用,否则它将不会被识别!
  • v-else-if

    • v-else-if 指令,顾名思义,充当 v-if 的“else-if 块”,可以连续使用:
    • 注意:v-else-if 指令必须配合 v-if 指令一起使用,否则它将不会被识别!
    <!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>Document</title>
    </head>
    
    <body>
      <div id="app">
        <!-- 条件成立,展示 v-if 控制的元素 -->
        <!-- 条件不成立,展示 v-else 控制的元素 -->
        <p v-if="flag">条件成立</p>
        <p v-else>条件不成立</p>
    
        <hr>
        <h3 v-if="age>=18">成年人,可以抽烟喝酒烫头</h3>
        <h1 v-else>未成年,漫画 + 娃哈哈</h1>
    
        <hr>
    
        <p v-if="score === 'A'">优秀</p>
        <p v-else-if="score === 'B'">良好</p>
        <p v-else-if="score === 'C'">一般</p>
        <p v-else></p>
    
    
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          data: {
            flag: true,
            age: 18,
            // A -> 优秀
            // B -> 良好
            // C -> 一般
            // D -> 差
            score: 'A'
          }
        })
    
      </script>
    </body>
    
    </html>
    
6. 列表渲染指令
  • vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。v-for 指令需要使

  • 用 item in list 形式的特殊语法,其中:

    • list 是待循环的数组
    • item 是被循环的每一项
  • v-for 中的索引

  • v-for 指令还支持一个可选的第二个参数,即当前项的索引。

    • 语法格式为 (item, index) in list
    • 注意:v-for 指令中的 item 项和 index 索引都是形参,可以根据需要进行重命名。例如 (user, i) in userlist
    <!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>Document</title>
      <style>
        table {
          width: 600px;
          border-collapse: collapse;
        }
    
        td,
        th {
          border: 1px solid #efefef;
          line-height: 35px;
          font-size: 12px;
          text-align: center;
        }
      </style>
    </head>
    
    <body>
      <div id="app">
        <table>
          <thead>
            <tr>
              <th>id</th>
              <th>name</th>
              <th>age</th>
              <th>index</th>
            </tr>
          </thead>
          <tbody>
            <!-- 如果需要基于数组中的数据, -->
            <!-- 循环在页面上,渲染出 UI 结构相似的元素 -->
            <!-- 此时,要能够想起来使用 v-for 指令 -->
            <!-- 语法: -->
            <!-- v-for="数组中的每一项 in 数组" -->
            <!-- v-for="item in 数组" -->
            <!-- 技巧:要循环生成哪个 DOM 元素,就在它身上添加 v-for 指令 -->
    
            <!-- v-for 最完整的语法格式: -->
            <!-- v-for="(item, index) in 数组" -->
    
            <!-- 注意:只要用到了 v-for 指令,推荐大家都要加上 key 属性的绑定 -->
            <!-- 建议把 id 当作 key 的值 -->
            <!-- key 的值必须是“数字”或“字符串”,key 的值不能是对象或其他类型 -->
            <tr v-for="(item, index) in list" :key="item.id">
              <td>{{ item.id }}</td>
              <td>{{ item.name }}</td>
              <td>{{ item.age }}</td>
              <td>索引是:{{ index }}</td>
            </tr>
          </tbody>
        </table>
      </div>
     
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          data: {
            // 用户的数组
            list: [
              { id: 1, name: '老汤', age: 35 },
              { id: 2, name: '狗哥', age: 34 },
              { id: 3, name: '小彬彬', age: 18 },
              { id: 4, name: '杨耀', age: 20 }
            ]
          }
        })
      </script>
    </body>
    
    </html>
    
  • 使用 key 维护列表的状态

    • 当列表的数据变化时,默认情况下,vue 会尽可能的复用已存在的 DOM 元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
    • 为了给 vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能。此时,需要为每项提供一个唯一的 key 属性:
  • key 的注意事项

    1. key 的值只能是字符串或数字类型
    2. key 的值必须具有唯一性(即:key 的值不能重复)
    3. 建议把数据项 id 属性的值作为 key 的值(因为 id 属性的值具有唯一性)
    4. 使用 index 的值当作 key 的值没有任何意义(因为 index 的值不具有唯一性)
    5. 建议使用 v-for 指令时一定要指定 key 的值(既提升性能、又防止列表状态紊乱)
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
    </head>
    
    <style>
      li {
        list-style: none;
      }
    </style>
    
    <body>
      <!-- 在页面中声明一个将要被 vue 所控制的 DOM 区域 -->
      <div id="app">
    
        <!-- 添加用户的区域 -->
        <div>
          <input type="text" v-model="name">
          <button @click="addNewUser">添加</button>
        </div>
    
        <!-- 用户列表区域 -->
        <ul>
          <!-- 建议:今后只要用到了 v-for,尽量都绑定一个 key 值 -->
          <!-- key 值的类型:数字或字符串 -->
          <!-- key 的值必须具有唯一性 -->
          <!-- 不要把 index 索引当作 key 的值,因为 index 索引不具有唯一性 -->
          <!-- 记住:那索引值当作 key 只是心理安慰,没有任何意义 -->
          <li v-for="(user, index) in userlist" :key="user.id">
            <input type="checkbox" />
            姓名:{{user.name}}
          </li>
        </ul>
      </div>
    
      <script src="./lib/vue-2.6.12.js"></script>
      <script>
        const vm = new Vue({
          el: '#app',
          data: {
            // 用户列表
            userlist: [
              { id: 1, name: '张三疯' },
              { id: 2, name: '桑三炮' },
              { id: 3, name: '倪大野' }
            ],
            // 输入的用户名
            name: '',
            // 下一个可用的 id 值
            nextId: 4
          },
          methods: {
            // 点击了添加按钮
            addNewUser () {
              if (this.name === '') {
                this.userlist.unshift({ id: this.nextId, name: '禽兽' })
                this.name = ''
                this.nextId++
              } else {
                this.userlist.unshift({ id: this.nextId, name: this.name })
                this.name = ''
                this.nextId++
              }
    
            }
          },
        })
      </script>
    </body>
    
    </html>
    

4.3 自定义指令

image.png

1. 什么是自定义指令
  • vue 官方提供了 v-text、v-for、v-model、v-if 等常用的指令。
  • 除此之外 vue 还允许开发者自定义指令。
2. 自定义指令的分类
  • vue 中的自定义指令分为两类,分别是:
    • 私有自定义指令
    • 全局自定义指令
3. 私有自定义指令
  • 在每个 vue 组件中,可以在 directives 节点下声明私有自定义指令。示例代码如下:

image.png

directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
} }
}
4. 使用自定义指令
  • 在使用自定义指令时,需要加上 v- 前缀。示例代码如下:

image.png

5. 为自定义指令动态绑定参数值
  • 在 template 结构中使用自定义指令时,可以通过等号(=)的方式,为当前指令动态绑定参数值

image.png

6. 通过 binding 获取指令的参数值
  • 在声明自定义指令时,可以通过形参中的第二个参数,来接收指令的参数值:

image.png

7. update 函数
  • bind 函数只调用 1 次:当指令第一次绑定到元素时调用,当 DOM 更新时 bind 函数不会被触发。
  • update 函数会在每次 DOM 更新时被调用。示例代码如下:

image.png

8. 函数简写
  • 如果 bind 和update 函数中的逻辑完全相同,则对象格式的自定义指令可以简写成函数格式:

image.png

9. 全局自定义指令
  • 全局共享的自定义指令需要通过“Vue.directive()”进行声明,示例代码如下:

image.png

5.过滤器

5.1 过滤器概念

  • 过滤器(Filters)是 vue 为开发者提供的功能,常用于文本的格式化
  • 过滤器可以用在两个地方:
    1. 插值表达式
    2. v-bind 属性绑定。
  • 过滤器应该被添加在 JavaScript 表达式的尾部,由“管道符”进行调用

5.2 定义过滤器

  • 在创建 vue 实例期间,可以在 filters 节点中定义过滤器
<!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>Document</title>
</head>

<body>
  <div id="app">
    <!-- 调用过滤器的语法: -->
    <!-- <p>{{ message | 过滤器 }}</p> -->
    <!-- 注意:在调用过滤器的时候 | 叫做“管道符” -->
    <p>{{ message | capt }}</p>
    <p>{{ info | capt }}</p>
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script>
    // 声明过滤器的语法:
    // Vue.filter('过滤器的名字', 过滤器的fucntion函数)
    // 过滤器的本质:就是一个 function 函数
    // 过滤器的 function 函数,第一个形参,永远都是 | 前面那个值
    Vue.filter('capt', function (val) {
      // 注意:过滤器函数,必须 return 一个处理的结果,
      // 如果没有 return 任何结果,就是一个无效的过滤器

      // 1. 把 val 的首字母转为大写
      const result = val.charAt(0).toUpperCase() + val.slice(1)
      // 2. 把转化的结果,return 出去
      return result
    })

    const vm = new Vue({
      el: '#app',
      data: {
        message: 'hello vue.js',
        info: 'my name is xxx'
      }
    })
  </script>
</body>

</html>

5.3 私有过滤器和全局过滤器

  • 在 filters 节点下定义的过滤器,称为私有过滤器,因为它只能在当前 vm 实例所控制的 el 区域内使用。
  • 如果希望在多个 vue 实例之间共享过滤器,则可以按照如下的格式定义全局过滤器
<!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>Document</title>
</head>

<body>
  <div id="app">
    <!-- 调用过滤器的语法: -->
    <!-- <p>{{ message | 过滤器 }}</p> -->
    <!-- 注意:在调用过滤器的时候 | 叫做“管道符” -->
    <p>{{ message | capt }}</p>
    <p>{{ info | capt }}</p>
    <p>{{ message | test }}</p>
    <p>--------------</p>
    <p>{{ message | capt | test }}</p>
  </div>

  <hr>

  <div id="app2">
    <h3>{{ msg | capt }}</h3>
    <!-- <h3>{{ msg | test }}</h3> -->
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script>
    // 声明过滤器的语法:
    // Vue.filter('过滤器的名字', 过滤器的fucntion函数)
    // 过滤器的本质:就是一个 function 函数
    // 过滤器的 function 函数,第一个形参,永远都是 | 前面那个值
    Vue.filter('capt', function (val) {
      // 注意:过滤器函数,必须 return 一个处理的结果,
      // 如果没有 return 任何结果,就是一个无效的过滤器

      // 1. 把 val 的首字母转为大写
      const result = val.charAt(0).toUpperCase() + val.slice(1)
      // 2. 把转化的结果,return 出去
      return result
    })

    const vm = new Vue({
      el: '#app',
      data: {
        message: 'hello vue.js',
        info: 'my name is xxx'
      },
      // 私有过滤器节点
      filters: {
        // 形参中的 val 就是调用过滤器时候, | 前面那个值
        test(val) {
          return val + '~~'
        }
      }
    })

    const vm2 = new Vue({
      el: '#app2',
      data: {
        msg: 'welcome xxx'
      }
    })
  </script>
</body>

</html>

5.4 连续调用多个过滤器

  • 过滤器可以串联地进行调用
 <p>{{ message | capt | test }}</p>

5.5 过滤器传参

  • 过滤器的本质是 JavaScript 函数,因此可以接收参数
<!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>Document</title>
</head>

<body>
  <div id="app">
    <p>{{ msg | maxLength(3) }}</p>
    <p>{{ maxLength2(msg, 5) }}</p>
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script>
    Vue.filter('maxLength', function (val, endIndex = 3) {
      if (val.length <= endIndex) {
        return val
      }
      // 字符串的 slice 函数,接收俩参数:
      // 开始的下标(包含)
      // 结束的下标(不包含)
      // slice/substr/substring
      return val.slice(0, endIndex) + '...'
    })

    const vm = new Vue({
      el: '#app',
      data: {
        msg: '1234567890'
      },
      methods: {
        maxLength2(val, endIndex = 3) {
          if (val.length <= endIndex) {
            return val
          }
          // 字符串的 slice 函数,接收俩参数:
          // 开始的下标(包含)
          // 结束的下标(不包含)
          // slice/substr/substring
          return val.slice(0, endIndex) + '...'
        }
      },
    })
  </script>
</body>

</html>

5.6 过滤器的兼容性

  • 过滤器仅在 vue 2.x 和 1.x 中受支持,在 vue 3.x 的版本中剔除了过滤器相关的功能。

  • 在企业级项目开发中:

    • 如果使用的是 2.x 版本的 vue,则依然可以使用过滤器相关的功能
    • 如果项目已经升级到了 3.x 版本的 vue,官方建议使用计算属性或方法代替被剔除的过滤器功能

6. watch 侦听器

6.1 什么是 watch 侦听器

  • watch 侦听器允许开发者监视数据的变化,从而针对数据的变化做特定的操作。

6.2 使用 watch 检测用户名是否可用

  • 监听 username 值的变化,并使用 axios 发起 Ajax 请求,检测当前输入的用户名是否可用
// 侦听器
      watch: {
        async username (newName, oldName) {
          console.log('监视到了 username 值的变化。', newName, oldName)

          // 如果用户名为空,则 return,防止调用接口报错
          if (newName === '') return

          // 注意:如果调用某个函数,返回值是 Promise 实例,
          // 则可以使用 async/await 简化 Promise 的使用。
          const result = await axios.get('https://www.escook.cn/api/finduser/' + newName)
          console.log(result.data)
        }
      }

6.3 immediate 选项

  • 默认情况下,组件在初次加载完毕后不会调用 watch 侦听器。如果想让 watch 侦听器立即被调用,则需要使用 immediate 选项

示例代码如下:

<!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>Document</title>
</head>

<body>
  <div id="app">
    请输入值:<input type="text" v-model="username" placeholder="请输入值">
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script src="./lib/axios.js"></script>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        username: ''
      },
      // 侦听器
      watch: {
        async username (newName, oldName) {
          console.log('监视到了 username 值的变化。', newName, oldName)

          // 如果用户名为空,则 return,防止调用接口报错
          if (newName === '') return

          // 注意:如果调用某个函数,返回值是 Promise 实例,
          // 则可以使用 async/await 简化 Promise 的使用。
          const result = await axios.get('https://www.escook.cn/api/finduser/' + newName)
          console.log(result.data)
        },
        // 表示页面初次渲染好之后,就立即触发当前的 watch 侦听器
        immediate: true
      }
    })
  </script>
</body>

</html>

6.4 deep 选项

  • 如果 watch 侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到。此时需要使用 deep 选项

代码示例如下:

<!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>Document</title>
</head>

<body>
  <div id="app">
    <input type="text" v-model="goods.title">

    <button @click="updateGoods">修改 goods</button>
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        // 商品的信息对象
        goods: {
          title: '娃哈哈酸奶',
          price: 3,
          count: 200
        }
      },
      watch: {
        goods: {
          handler: function (newVal) {
            console.log(newVal)
          },
          // 如果监听的对象上的属性发生了变化,可以能够触发侦听器
          // 深度监听
          deep: true
        }
      },
      methods: {
        updateGoods () {
          this.goods = {
            title: '牛奶',
            price: 5,
            count: 100
          }
        }
      },
    })
  </script>
</body>

</html>

6.5 监听对象单个属性的变化

  • 如果只想监听对象中单个属性的变化,则可以按照如下的方式定义 watch 侦听器:
<!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>Document</title>
</head>

<body>
  <div id="app">
    <input type="text" v-model="goods.title">
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        // 商品的信息对象
        goods: {
          title: '娃哈哈酸奶',
          price: 3,
          count: 200
        }
      },
      watch: {
        /* 'goods.title': {
          handler: function (newVal, oldVal) {
            console.log(newVal, oldVal)
          }
        } */

        // 如果在定义侦听器的时候,必须要添加 immediate 或 deep 选项,需要把侦听器定义为【对象格式】
        // 否则,直接把侦听器定义为【函数格式】即可
        'goods.title'(newVal, oldVal) {
          console.log(newVal, oldVal)
        }
      }
    })
  </script>
</body>

</html>

7. 计算属性

7.1 什么是计算属性

  • 计算属性指的是通过一系列运算之后,最终得到一个属性值。
  • 这个动态计算出来的属性值可以被模板结构或 methods 方法使用。示例代码如下:
<!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>Document</title>
</head>

<body>
  <div id="app">
    <h3>count 的值是:{{ count }}</h3>

    <!-- 不建议这么写(浪费性能) -->
    <!-- <p>count * count 的值是:{{count * count}}</p>
    <p>count * count 的值是:{{count * count}}</p>
    <p>count * count 的值是:{{count * count}}</p> -->

    <!-- 3. 计算属性在使用的时候,不要当作函数去调用, -->
    <!--    而是当作普通的属性,来直接使用就好了 -->
    <p>count * count 的值是:{{ num }}</p>
    <p>count * count 的值是:{{ num }}</p>
    <p>count * count 的值是:{{ num }}</p>
  </div>

  <script src="./lib/vue-2.6.12.js"></script>
  <script>
    const vm = new Vue({
      el: '#app',
      data: {
        count: 2
      },
      // 计算属性
      computed: {
        // 1. 计算属性在定义的时候,需要被定义成函数
        // 4. 注意:计算属性,会缓存上一次计算的结果
        // 5. 只有计算属性中依赖的数据项发生变化的时候,才会重新对计算属性求值
        num() {
          console.log('执行了 num 这个计算属性')
          // 2. 计算属性,必须 return 一个计算的结果,否则,就是无效的计算属性
          return this.count * this.count
        }
      }
    })
  </script>
</body>

</html>

7.2 计算属性的特点

  • 虽然计算属性在声明的时候被定义为方法,但是计算属性的本质是一个属性
  • 计算属性会缓存计算的结果,只有计算属性依赖的数据变化时,才会重新进行运算

7.3 计算属性-案例

效果图:
image.png

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <script src="./lib/vue-2.6.12.js"></script>
  <style>
    .box {
      width: 200px;
      height: 200px;
      border: 1px solid #ccc;
    }
  </style>
</head>

<body>
  <div id="app">
    <div>
      <span>R:</span>
      <input type="text" v-model.number="r">
    </div>
    <div>
      <span>G:</span>
      <input type="text" v-model.number="g">
    </div>
    <div>
      <span>B:</span>
      <input type="text" v-model.number="b">
    </div>
    <hr>

    <!-- 专门用于呈现颜色的 div 盒子 -->
    <!-- 如果动态为元素的 style 绑定样式,需要遵守如下的语法规则: -->
    <!-- :style="样式对象" -->
    <!-- :style="{ 样式的属性: 值, 样式的属性: 值 }" -->
    <div class="box" :style="{ 'background-color': rgb }">
    </div>
    <!-- 计算属性在使用的时候,当作普通属性来用就好 -->
    <p>{{ rgb }}</p>
    <button @click="show">按钮</button>
  </div>

  <script>
    // 创建 Vue 实例,得到 ViewModel
    var vm = new Vue({
      el: '#app',
      data: {
        // 红色
        r: 0,
        // 绿色
        g: 0,
        // 蓝色
        b: 0
      },
      // 计算属性
      computed: {
        // 1. 计算属性,在定义的时候,要定义成函数
        // 注意:只要计算属性中,用到的 data 数据发生了变化,就会重新对计算属性求值
        rgb() {
          // 2. 必须 return 一个结果
          return `rgb(${this.r}, ${this.g}, ${this.b})`
        }
      },
      methods: {
        // 点击按钮,在终端显示最新的颜色
        show() {
          // 在 methods 函数中,要访问计算属性的值,要通过 this.计算属性 来访问
          console.log(this.rgb)
        }
      },
    });
  </script>
</body>

</html>

8. vue-cli

8.1 单页面应用程序

  • 单页面应用程序(英文名:Single Page Application)简称 SPA,顾名思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。

8.2 什么是 vue-cli

  • vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程。
  • 引用自 vue-cli 官网上的一句话:
  • 程序员可以专注在撰写应用上,而不必花好几天去纠结 webpack 配置的问题。
  • 中文官网:https://cli.vuejs.org/zh/

8.3 安装和使用

  • vue-cli 是 npm 上的一个全局包,使用 npm install 命令,即可方便的把它安装到自己的电脑上:npm install -g @vue/cli

  • 基于 vue-cli 快速生成工程化的 Vue 项目:vue create 项目的名称

8.4 vue 项目的运行流程

  • 在工程化的项目中,vue 要做的事情很单纯:通过 main.js 把 App.vue 渲染到 index.html 的指定区域中。
  • 其中:
    • App.vue 用来编写待渲染的模板结构
    • index.html 中需要预留一个 el 区域
    • main.js 把 App.vue 渲染到了 index.html 所预留的区域中

8.5 Vue 组件库

1. vue-cli 手动选择要安装的功能
  • 目标:在使用 vue-cli 创建项目的时候,能够手动选择要安装的功能
  • 回顾之前使用 vue-cli 创建项目的步骤:
    1. 运行 vue create 项目名称
    2. 选择 Default([vue 2] babel, eslint)

image.png

  • 存在的问题:

    1. 只包含特定的 3 个功能(vue2 + babel + eslint)
    2. 不包含 vue-router、vuex 等其它功能
  • 推荐的方式:选择 Manually select features

  • 好处:在项目创建期间,能够选择并安装更多的功能

    image.png

  • 手动选择要安装的功能(1/10)

    1. 运行 vue create 项目名称
    2. 选择 Manually select features

image.png

  • 手动选择要安装的功能(2/10)

    • 推荐选择并安装以下的 6 个功能:

    image.png

    1. ↑↓箭头切换选中项
    2. 空格切换选中状态
    3. *号表示安装选中的功能
  • 手动选择要安装的功能(3/10)

    • 选择要安装的 vue 版本(建议选择 2.x):

    image.png

  • 手动选择要安装的功能(4/10)

    • 是否使用 history 模式的路由(建议输入 n):

    image.png

  • 手动选择要安装的功能(5/10)

    • 选择要使用的 CSS 预处理器(建议选择 Less):

    image.png

  • 手动选择要安装的功能(6/10)

    • 选择要使用的 ESLint 语法规则(建议选择 ESLint + Standard config):

    image.png

  • 手动选择要安装的功能(7/10)

    • 选择额外的 lint 功能(建议选择 Lint on save,在 Ctrl + S 的时候检测代码是否符合规范):

    image.png

  • 手动选择要安装的功能(8/10)

    • 把第三方插件的配置选项放到哪个配置文件中(建议选择 In dedicated config files,表示:独立的配置文件):

    image.png

  • 手动选择要安装的功能(9/10)

    • 是否把刚才所有的操作保存为预设,方便下次直接基于预设,一键生成项目(建议输入 y):

    image.png

  • 手动选择要安装的功能(10/10)

    • 为预设提供一个好记的名字(建议输入英文的预设名称):

    image.png

2. ESLint 基本语法

目标:能够知道 ESLint 常见的语法规则,并在实际开发中遵守这些规则

2.1 什么是 ESLint?
  • 官方概念:ESLint 是可组装的 JavaScript 和 JSX 检查工具。
  • 通俗理解:一个工具,用来约束团队成员的代码风格。
  • 好处:保证团队协作开发时,编写出来的代码风格保持一致。
  • 例如:
    1. JS 中的字符串,统一使用单引号表示
    2. 代码缩进,统一使用两个空格
    3. 不允许出现 ≥2 个的连续空行
2.2 常见的 ESLint 规则

image.png

  • 更多的 ESLint 规则,请查阅官方文档 https://eslint.bootcss.com/docs/rules/
2.3 修改 vue-cli 项目的语法规则
  1. 找到项目根目录下的 .eslintrc.js 配置文件
  2. 在 rules 配置选项中,修改默认的语法规则

image.png

9. vue 组件

9.1 什么是组件化开发

  • 组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。

9.2 vue 中的组件化开发

  • vue 是一个支持组件化开发的前端框架。
  • vue 中规定:组件的后缀名是 .vue。之前接触到的 App.vue 文件本质上就是一个 vue 的组件。

9.3 vue 组件的三个组成部分

  • 每个 .vue 组件都由 3 部分构成,分别是:
    • template -> 组件的模板结构
    • script -> 组件的 JavaScript 行为
    • style -> 组件的样式
  • 其中,每个组件中必须包含 template 模板结构,而 script 行为和 style 样式是可选的组成部分。
1. template
  • vue 规定:每个组件对应的模板结构,需要定义到 <template> 节点中。
  • 注意:
    • template 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的 DOM 元素
    • template 中只能包含唯一的根节点
2. script
  • vue 规定:开发者可以在 <script>节点中封装组件的 JavaScript 业务逻辑。
  • .vue 组件中的 data 必须是函数
  • vue 规定:.vue 组件中的 data 必须是一个函数,不能直接指向一个数据对象。
3. style
  • vue 规定:组件内的 <style> 节点是可选的,开发者可以在<style>节点中编写样式美化当前组件的 UI 结构
  • <style> 标签上添加 lang="less" 属性,即可使用 less 语法编写组件的样式

vue.png

9.4 组件之间的父子关系

image.png

1. 使用组件的三个步骤

image.png

  • 步骤1:使用 import 语法导入需要的组件
  • 步骤2:使用 components 节点注册组件
  • 步骤3:以标签形式使用刚才注册的组件
2. 通过 components 注册的是私有子组件
  • 例如:

    • 在组件 A 的 components 节点下,注册了组件 F。
    • 则组件 F 只能用在组件 A 中;不能被用在组件 C 中。
  • 请大家思考两个问题:

    1. 为什么 F 不能用在组件 C 中?
    2. 怎样才能在组件 C 中使用 F?
3. 注册全局组件

在 vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。示例代码如下:

image.png

9.5 组件的 props

  • props 是组件的自定义属性,在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性

  • 它的语法格式如下:

image.png

1. props 是只读的
  • vue 规定:组件中封装的自定义属性是只读的,程序员不能直接修改 props 的值。否则会直接报错:

image.png

  • 要想修改 props 的值,可以把 props 的值转存到 data 中,因为 data 中的数据都是可读可写的!

image.png

2. props 的 default 默认值
  • 在声明自定义属性时,可以通过 default 来定义属性的默认值。示例代码如下:

image.png

3. props 的 type 值类型
  • 在声明自定义属性时,可以通过 type 来定义属性的值类型。示例代码如下:

image.png

4. props 的 required 必填项
  • 在声明自定义属性时,可以通过 required 选项,将属性设置为必填项,强制用户必须传递属性的值。示例代码如下:

image.png

5. 组件之间的样式冲突问题
  • 默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。
  • 导致组件之间样式冲突的根本原因是:
    • 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的
    • 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素

9.6 组件的基本使用

1. 思考:如何解决组件样式冲突的问题
  • 为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器来控制样式的作用域,示例代码如下:

image.png

2. style 节点的 scoped 属性
  • 为了提高开发效率和开发体验,vue 为 style 节点提供了 scoped 属性,从而防止组件之间的样式冲突问题:

image.png

3. /deep/ 样式穿透
  • 如果给当前组件的 style 节点添加了 scoped 属性,则当前组件的样式对其子组件是不生效的。如果想让某些样式对子组件生效,可以使用 /deep/ 深度选择器。

image.png

9.7 动态组件

1. 什么是动态组件
  • 动态组件指的是动态切换组件的显示与隐藏
2. 如何实现动态组件渲染
  • vue 提供了一个内置的 <component> 组件,专门用来实现动态组件的渲染。示例代码如下:

image.png

  • component 标签是专门用来占位的
  • 给 is 属性所表示的组件,来进行展位
<component is="组件的注册名称"></component>
3. 使用 keep-alive 保持状态
  • 默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 <keep-alive> 组件保持动态组件的状态。示例代码如下:
 <keep-alive include="Right,Left">
        <component :is="comName"></component>
 </keep-alive>
  • keep-alive 可以保证内部的组件不会被销毁
  • 注意:默认情况下,keep-alive 会缓存内部所有的组件
  • include=“Right” 表示:只缓存名字叫 Right 的组件,其它组件不会被缓存
  • 注意:在 include 中,逗号前后千万不要加空格,否则会有问题
4. keep-alive 对应的生命周期函数
  • 当组件被缓存时,会自动触发组件的 deactivated 生命周期函数。
  • 当组件被激活时,会自动触发组件的 activated 生命周期函数。
 destroyed() {
    console.log('destroyed')
  },
  // 组件被激活的时候,会自动触发 activated 生命周期函数
  // 组件在被激活的时候,以及组件第一次被创建的时候,都会触发 activated 生命周期函数
  activated() {
    console.log('---- activated ----', '组件被激活了')
  },
  // 组件被缓存的时候,会自动触发 deactivated 生命周期函数
  // 只有组件被缓存的时候,才会触发 deactivated 生命周期函数
  deactivated() {
    console.log('---- deactivated ----', '组件被缓存了')
  }
5. keep-alive 的 include 属性
  • include 属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间使用英文的逗号分隔
      <!-- keep-alive 可以保证内部的组件不会被销毁 -->
      <!-- 注意:默认情况下,keep-alive 会缓存内部所有的组件 -->
      <!-- include="Right" 表示:只缓存名字叫 Right 的组件,其它组件不会被缓存 -->
      <!-- 注意:在 include 中,逗号前后千万不要加空格,否则会有问题 -->
      <keep-alive include="Right,Left">
        <component :is="comName"></component>
      </keep-alive>

10. 组件之间的数据共享

10.1 组件之间的关系

  • 在项目开发中,组件之间的最常见的关系分为如下两种:
    1. 父子关系
    2. 兄弟关系

image.png

10.2 父子组件之间的数据共享

  • 父子组件之间的数据共享又分为:
    1. 父 -> 子共享数据
    2. 子 -> 父共享数据
1. 父组件向子组件共享数据
  • 父组件向子组件共享数据需要使用自定义属性。示例代码如下:

image.png

2. 子组件向父组件共享数据
  • 子组件向父组件共享数据使用自定义事件。示例代码如下:

image.png

10.3 兄弟组件之间的数据共享

  • 在 vue2.x 中,兄弟组件之间数据共享的方案是 EventBus
  • EventBus 的使用步骤
    1. 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象
    2. 在数据发送方,调用 bus.$emit('事件名称', 要发送的数据) 方法触发自定义事件
    3. 在数据接收方,调用 bus.$on('事件名称', 事件处理函数) 方法注册一个自定义事件
      image.png

11. vuex

11.1 Vuex 起步

1. Vuex 是什么
  • Vuex 是 vue 项目中实现大范围数据共享的技术方案。

  • 作用:能够方便、高效地实现组件之间的数据共享

image.png

2. 使用 Vuex 的好处
  1. 数据的存取一步到位,不需层层传递
  2. 数据的流动非常清晰
  3. 存储在 Vuex 中的数据都是响应式的
3. 在项目中安装和配置 Vuex
  • 步骤:
    1. 前期的准备:安装 Vuex 的依赖包
    2. 封装 Store 模块
    3. 导入并挂载 Store 的实例对象
3.1 安装 Vuex 的依赖包
  • 运行如下的 npm 命令,在把 Vuex 安装为项目的依赖包:

image.png

3.2 封装 Store 模块
  • 主要的实现步骤如下:
    1. 导入 Vue 和 Vuex 依赖包
    2. 把 Vuex 安装为 Vue 的插件
    3. 创建 store 的实例对象
    4. 向外共享 store 的实例对象

image.png

  • 在store/index.js文件中
  1. 导入包 vue 和 vuex
// 这是 vuex 的 Store 模块
// 1. 导入包 vue 和 vuex
import Vue from 'vue'
import Vuex from 'vuex'
  1. 调用 Vue.use() 函数把 Vuex 安装为插件
// 2. 调用 Vue.use() 函数把 Vuex 安装为插件
Vue.use(Vuex)
  1. new Vuex.Store() 创建 store 的实例对象
// 3. new Vuex.Store() 创建 store 的实例对象
const store = new Vuex.Store({
  // 开启 vuex 的严格模式,如果检测到了组件直接修改全局数据,
  // 则立即终端报错!
  // vue 官方建议程序员:在项目上线的时候,一定要把 strict: true 去掉,
  // 因为它会降低 vuex 的性能
  strict: true,
  // 全局共享的数据,都存储到 state 这个对象中
  state: {
    count: 0
  },
  // 专门用来修改全局的数据
  mutations: {
    // 1. mutation 必须是函数
    // 2. 第一个形参,永远都是 state
    add(state, n) {
      state.count += n
    }
  },
  // 专门处理异步操作
  // Ajax 请求、延迟器、定时器...
  actions: {
    // 定义一个异步自增的函数
    // action 函数的第一个形参,永远都是 ctx,
    // ctx 就是 new 出来的 store 实例对象
    addAsync(ctx, n) {
      // 1. 延迟1秒
      setTimeout(() => {
        // 2. 调用 add 这个 mutation 函数
        // ctx.commit() 函数的作用,就是调用指定名称的 mutation
        ctx.commit('add', n)
      }, 1000)
    }
  }
})
  1. 向外导出 store 的实例对象
// 4. 向外导出 store 的实例对象
export default store
3.3 把 Store 实例挂载到 Vue 实例上
  • 主要的实现步骤:
    1. 导入 store 模块
    2. 挂载 store 实例对象

image.png

  • 在main.js中
  1. 导入 store 模块
// 1. 导入 store 模块
import store from '@/store'
  1. 挂载 store 实例对象
new Vue({
  render: h => h(App),
  // 2. 把 store 模块挂载到 Vue 实例上
  // (挂载完毕之后,每个 .vue 组件中,就可以访问全局共享的数据啦)
  // store: new出来的store实例
  // store: store
  store
}).$mount('#app')

11.2 State 的基本使用

1. 什么是 State
  • 概念:State 本质上就是 Object 对象

  • 作用:用来存储全局共享的数据

  • 基本用法: store 的实例对象

 // 全局共享的数据,都存储到 state 这个对象中
  state: {
    count: 0
  },
2. 组件访问 State 数据
2.1 第一种方式
  • 在每个 Vue 组件中,可以通过 this.$store.state.全局数据名称 访问 Store 中的数据。

image.png

2.2 第二种方式
  • 基于 Vuex 提供的 mapState 辅助函数,可以方便的把 Store 中指定的数据,映射为当前组件的计算属性

image.png

  1. 按需导入一个辅助函数 mapState
import { mapState } from 'vuex'
  1. 把 Store 中指定的数据,映射为当前组件的计算属性
//mapState(['全局数据的名字', '全局数据的名字'])
  computed: {
    // ...obj
    // ...result
    ...mapState(['count'])
  },
  • 结论:在实际开发中,不要在组件中直接修改全局的数据

  • 原因:会导致 vue-devtools 调试工具失效,无法检测到 vuex 中数据的变化

  • 通过 this.$store.commit() 就可以调用到指定名称的 mutation 函数

  • 通过 this.$store.dispatch('action函数的名字') 函数,

 this.$store.commit('add', 1)
 // 可以调用指定名称的 action 函数
 this.$store.dispatch('addAsync', 2)
  • 在组件使用 State 中数据的两种方式分别是什么?
    1. this.$store.state.数据项的名字
    2. mapState 辅助函数 + computed 计算属性
2.3 拓展:mapState 辅助函数的原理

image.png

// 1. 按需导入一个辅助函数 mapState
import { mapState } from 'vuex'

//#region 注释
// mapState(['全局数据的名字', '全局数据的名字'])
// 调用结果 {count: ƒ}
// 2. 把 Store 中指定的数据,映射为当前组件的计算属性

// const result = mapState(['count'])
// console.log(result)

// const obj = {
//   // 自定义计算属性,名字叫做 count
//   count() {
//     // 在计算属性中,必须 return 一个计算的结果
//     return this.$store.state.count
//   }
// }
//#endregion

export default {
  name: 'Left',
  // 计算属性
  computed: {
    // ...obj
    // ...result
    ...mapState(['count'])
  },

11.3 Mutation 的基本使用

1. 怎样修改 State 中的数据
  • 请大家思考:我们能否在组件中直接修改 Vuex 中的数据?

image.png

  • 结论:能直接修改,但是不推荐!Vuex 官方也禁止我们直接修改!
  • 原因:会导致修改来源不明确的问题,不利于调试和后期的维护。
2. Mutation 是什么
  • Mutation 本质上是 JavaScript 函数,专门用来变更 Store 中的数据

image.png

  • 特点:想要修改 State 中的数据,只能调用 Mutation 方法

  • 好处:能够确保修改来源的唯一性,方便调试和后期维护。

3. State、组件、Mutation 之间的关系

image.png

  • State:全局存储共享数据的地方
  • Vue 组件:使用数据的地方
  • Mutation:专门负责修改 State 中的数据
4. Mutation 的使用步骤
  1. 在 Vuex 中定义 Mutation 方法
  2. 组件中调用 Mutation 方法 this.$store.commit('方法名')
    image.png
  // 专门用来修改全局的数据
  mutations: {
    // 1. mutation 必须是函数
    // 2. 第一个形参,永远都是 state
    add(state, n) {
      state.count += n
    }
  },
  • 注意:
    1. mutation 必须是函数
    2. 第一个形参,永远都是 state
4.1 载荷(Payload)
  • Vuex 中的载荷就是参数的意思,通过载荷可以提高 Mutation 方法的通用性。例如:
    1. 第一个形参,永远都是 state
    2. 第二形参,Payload来传递调用者传递过来的参数

image.png

4.2 提交载荷(Payload)
  • 在组件中,可以通过 this.$store.commit() 方法的第二个参数来提交载荷(参数),示例代码如下:

image.png

5. mapMutations 辅助函数
  • 基于 Vuex 提供的 mapMutations 辅助函数,可以方便的把 Store 中指定的方法,映射为当前组件的 methods

image.png

  • mapMutations 辅助函数的用法示例

image.png

11.4 Action 的基本使用

1. Mutation 必须是同步函数
  • 在项目开发中,为了保证 Store 中状态的每一次变化都是可追踪的
  • Vuex 规定: Mutation 必须是同步函数。否则,vue-devtools 将无法正常追踪 Store 中数据的变化,这对大型项目的开发调试是灾难性的!

image.png

2. Action 是什么
  • Action 本质上是 JavaScript 函数,专门用来处理 Vuex 中的异步操作。

image.png

  • Action 把异步操作的结果,转交给 Mutation,由 Mutation 负责修改数据源。
3. 定义 Action 方法

image.png

4. 调用 Action 方法
4.1 第一种方式
  • 在组件中,通过 this.$store.dispatch('xxx') 方法,即可触发指定名称的 Action 方法。示例代码如下:
 // 可以调用指定名称的 action 函数
      this.$store.dispatch('addAsync', 2)
  1. 在 Action 方法中定义载荷
    • 在 Action 方法中,可以通过第二个形参的位置来定义载荷参数。示例代码如下:
      image.png
 // 定义一个异步自增的函数
    // action 函数的第一个形参,永远都是 ctx,
    // ctx 就是 new 出来的 store 实例对象
    addAsync(ctx, n) {
      // 1. 延迟1秒
      setTimeout(() => {
        // 2. 调用 add 这个 mutation 函数
        // ctx.commit() 函数的作用,就是调用指定名称的 mutation
        ctx.commit('add', n)
      }, 1000)
    }
  1. 调用 Action 方法时提交载荷
  • 通过 this.$store.dispatch() 方法的第二个参数,即可提交载荷。示例代码如下:

image.png

4.2 第二种方式
  • mapActions 辅助函数
    • 基于 Vuex 提供的 mapActions 辅助函数,可以方便的把 Store 中指定的 Action,映射为当前组件的 methods

image.png

  • mapActions 辅助函数的用法示例

image.png

11.5 Getter 的基本使用

1. 组件中计算属性的局限性
  • 组件中的计算属性复用性比较低。例如:

image.png

  • 如果有多个组件需要用到此计算属性,我们需要在多个组件之间复制、粘贴这个函数。
2. Getter 是什么
  • Getter 本质上是 JavaScript 函数。
  • 作用:它是 Vuex 中的计算属性,当 Store 数据源发生变化时,Getter 的返回值会自动更新。

image.png

3. 定义 Getter 方法

image.png

4. 访问 Getter
4.1 第一种方式
  • 在组件中,可以通过 this.$store.getters.xxx 来访问指定 getter 的值。示例代码如下:

image.png

4.2 第二种方式
  • 基于 mapGetters 辅助函数,可以把 store 中的 getter 映射为当前组件的计算属性。示例代码如下:

image.png

11.6 Module 的基本使用

1. 思考:当前遇到的问题

image.png

  • 所有的全局数据、方法都集中在了一起,导致 Vuex 的结构混乱,不利于现阶段的开发和后期的维护。
2. Module 是什么
  • Vuex 中的 Module 表示按照模块化的开发思想,把不同的数据和方法,按照彼此的关联关系进行封装。

image.png

3. 定义模块
  • 每个模块都是彼此独立的,都可以拥有自己的 state、mutations、actions、getters 节点

image.png

4. 注册模块

image.png

  • 注意:
  1. 拆了模块之后,一定要在 store/index.js 中,对模块进行组装,否则模块不会生效
  2. 只要拆模块了,必须开启命名空间
    namespaced: true,
  1. 在 vuex 独立的模块中,state 不能是对象,必须是 function
// 计数器的 vuex 模块
export default {
  // 注意:只要拆模块了,必须开启命名空间
  namespaced: true,
  // 在 vuex 独立的模块中,state 不能是对象,必须是 function
  state() {
    return {
      // 在这里定义数据
      count: 0,
      total: 9
    }
  },
  mutations: {
    show() {
      console.log('这是【计数器模块】中的show函数')
    },
    add(state, n) {
      state.count += n
    }
  },
  actions: {
    addAsync(ctx, n) {
      setTimeout(() => {
        ctx.commit('add', n)
      }, 1000)
    }
  }
}

5. namespaced(命名空间)
  • namespaced(命名空间)可以解决不同模块之间成员名称冲突的问题。在实际项目开发中,建议为每个 Module 模块都开启命名空间!
  • 在定义模块时,只需在模块的根节点中声明 namespaced: true 选项,即可为当前模块开启命名空间

image.png

6. 访问Module
6.1 通过模块的注册名称访问模块下的成员
  • 当模块启用了 namespaced: true 选项之后,模块就有了自己的命名空间。
  • 此时,模块内的成员需要通过模块的注册名称才可以访问到。示例代码如下:

image.png

6.2 访问命名空间下的 state 数据
  • 在组件中访问命名空间下的 state 数据时,建议使用 mapState 函数来简化访问的过程。示例代码如下:

image.png

6.3 访问命名空间下的 mutation 方法
  • 在组件中访问命名空间下的 mutation 方法时,建议使用 mapMutations 函数来简化访问的过程:

image.png

6.4 访问命名空间下的 action 和 getter
  • 建议使用 mapActions 和 mapGetters 函数来简化访问的过程,示例代码如下:

image.png

12.组件的生命周期

12.1 生命周期 & 生命周期函数

  • 生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段

  • 生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行

  • 注意:生命周期强调的是时间段,生命周期函数强调的是时间点。

12.2 组件生命周期函数的分类

image.png

12.3 生命周期图示

image.png

13. ref 引用

13.1 什么是 ref 引用

  • ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素组件的引用。

  • 每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向一个空对象

13.2 使用 ref 引用 DOM 元素

  • 如果想要使用 ref 引用页面上的 DOM 元素,则可以按照如下的方式进行操作:

image.png

13.3 使用 ref 引用组件实例

  • 如果想要使用 ref 引用页面上的组件实例,则可以按照如下的方式进行操作:

image.png

13.4 控制文本框和按钮的按需切换

  • 通过布尔值 inputVisible 来控制组件中的文本框与按钮的按需切换。示例代码如下:

image.png

13.5 让文本框自动获得焦点

  • 当文本框展示出来之后,如果希望它立即获得焦点,则可以为其添加 ref 引用,并调用原生 DOM 对象的.focus() 方法即可。示例代码如下:

image.png

13.6 this.$nextTick(cb) 方法

  • 组件的 $nextTick(cb) 方法,会把 cb 回调推迟到下一个 DOM 更新周期之后执行。
  • 通俗的理解是:等组件的DOM 更新完成之后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。

image.png

14. 路由

14.1 路由的基本概念与原理

  • 路由是一个比较广义和抽象的概念,路由的本质就是对应关系
  • 在开发中,路由分为:
    • 后端路由
    • 前端路由
1. 后端路由
  • 概念:根据不同的用户 URL 请求,返回不同的内容
  • 本质:URL 请求地址与服务器资源之间的**对应关系 **

image.png

  • SPA(Single Page Application)
  • 后端渲染(存在性能问题)
  • Ajax前端渲染(前端渲染提高性能,但是不支持浏览器的前进后退操作)
  • SPA(Single Page Application)单页面应用程序:整个网站只有一个页面,内容的变化通过Ajax局部更新实现、同时支持浏览器地址栏的前进和后退操作
  • SPA实现原理之一:基于URL地址的hash(hash的变化会导致浏览器记录访问历史的变化、但是hash的变化不会触发新的URL请求)
  • 在实现SPA过程中,最核心的技术点就是前端路由
2. 前端路由
  • 概念:根据不同的用户事件,显示不同的页面内容
  • 本质:用户事件与事件处理函数之间的对应关系

image.png

14.2 vue-router的基本使用

1. 基本使用步骤
  1. 引入相关的库文件
<!-- 导入 vue 文件,为全局 window 对象挂载 Vue 构造函数 -->
<script src="./lib/vue_2.5.22.js"></script>

<!-- 导入 vue-router 文件,为全局 window 对象挂载 VueRouter 构造函数 -->
<script src="./lib/vue-router_3.0.2.js"></script>
  1. 添加路由链接
  • router-link 是 vue 中提供的标签,默认会被渲染为 a 标签
  • to 属性默认会被渲染为 href 属性
  • to 属性的值默认会被渲染为 # 开头的 hash 地址
<!-- router-link 是 vue 中提供的标签,默认会被渲染为 a 标签 -->
<!-- to 属性默认会被渲染为 href 属性 -->
<!-- to 属性的值默认会被渲染为 # 开头的 hash 地址 -->

<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
  1. 添加路由填充位
  • 路由填充位(也叫做路由占位符)
  • 将来通过路由规则匹配到的组件,将会被渲染到 router-view 所在的位置
<!-- 路由填充位(也叫做路由占位符) -->
<!-- 将来通过路由规则匹配到的组件,将会被渲染到 router-view 所在的位置 -->

<router-view></router-view>
  1. 定义路由组件
var User = {
    template: '<div>User</div>'
}

var Register = {
    template: '<div>Register</div>'
}
  1. 配置路由规则并创建路由实例
  • 每个路由规则都是一个配置对象,其中至少包含 path 和 component 两个属性
    • path 表示当前路由规则匹配的 hash 地址
    • component 表示当前路由规则对应要展示的组件
// 创建路由实例对象

var router = new VueRouter({

// routes 是路由规则数组

routes: [

// 每个路由规则都是一个配置对象,其中至少包含 path 和 component 两个属性:

// path 表示当前路由规则匹配的 hash 地址

// component 表示当前路由规则对应要展示的组件

{path:'/user',component: User},

{path:'/register',component: Register}

]

})
  1. 把路由挂载到 Vue 根实例中
new Vue({

el: '#app',

// 为了能够让路由规则生效,必须把路由对象挂载到 vue 实例对象上

router

});
  1. 下载vue-router模块到当前工程
yarn add vue-router
  1. 在main.js中引入VueRouter函数
import VueRouter from 'vue-router'
  1. 添加到Vue.use()身上 – 注册全局RouterLink和RouterView组件
Vue.use(VueRouter)
  1. 创建路由规则数组 – 路径和组件名对应关系
const routes = []
  1. 用规则生成路由对象
const router = new VueRouter({

  routes

})
  1. 创建和挂载根实例。
new Vue({

  router

})
  1. 用router-view作为挂载点, 切换不同的路由页面
<router-view></router-view>
2. 路由重定向
  • 路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面;

  • 通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:

var router = new VueRouter({

routes: [

// 其中,path 表示需要被重定向的原地址,redirect 表示将要被重定向到的新地址

{path:'/', redirect: '/user'},

{path:'/user',component: User},

{path:'/register',component: Register}

]

})
3. Vue路由-404页面
路由最后, path匹配*(任意路径) – 前面不匹配就命中最后这个

14.3 vue-router嵌套路由

1. 嵌套路由功能分析
  • 点击父级路由链接显示模板内容
  • 模板内容中又有子级路由链接
  • 点击子级路由链接显示子级模板内容

image.png

2. 父路由组件模板
  • 父级路由链接
  • 父组件路由填充位
< p >
    <router-link to="/user">User</router-link>
    <router-link to="/register">Register</router-link>
</p>
  <div>
    <!-- 控制组件的显示位置 --> 
    <router-view></router-view>
  </div>
3. 子级路由模板
  • 子级路由链接
  • 子级路由填充位
const Register = {
  template: `<div>
  <h1>Register 组件</h1>
  <hr/>
  <router-link to="/register/tab1">Tab1</router-link>
  <router-link to="/register/tab2">Tab2</router-link>
  <!-- 子路由填充位置 --> <router-view/>
  </div>`
  }
4. 嵌套路由配置
  • 父级路由通过children属性配置子级路由
const router = new VueRouter({
  routes: [
    { path: '/user', component: User },
    {
      path: '/register',
      component: Register,
      // 通过 children 属性,为 /register 添加子路由规则
      children: [
        { path: '/register/tab1', component: Tab1 },
        { path: '/register/tab2', component: Tab2 }
      ]
    }]
})

14.4 vue-router动态路由匹配

1. 思考:
<!– 有如下 3 个路由链接 --> <router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>

// 定义如下三个对应的路由规则,是否可行???
{ path: '/user/1', component: User }
{ path: '/user/2', component: User }
{ path: '/user/3', component: User }
2. 应用场景:通过动态路由参数的模式进行路由匹配
var router = new VueRouter({
  routes: [
  // 动态路径参数 以冒号开头
  { path: '/user/:id', component: User }
  ]
  })
  
const User = {
  // 路由组件中通过$route.params获取路由参数
  template: '<div>User {{ $route.params.id }}</div>'
}
  • 结论:为了让路由规则的通用性更好,可以把可变的部分,
  • 通过 : 的形式,定义为“动态参数项”
  • 注意:冒号后的名字,是任意起的,推荐起一个有意义的名字
  • 通过 this.$route.params.xxx 访问到路由规则中匹配的参数
3. 路由组件传递参数
  • $route与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦
3.1 props的值为布尔类型
const router = new VueRouter({
  routes: [
    // 如果 props 被设置为 true,route.params 将会被设置为组件属性
    { path: '/user/:id', component: User, props: true }]
})
const User = {
  props: ['id'], // 使用 props 接收路由参数
  template: '<div>用户ID:{{ id }}</div>' // 使用路由参数
}
3.2 props的值为对象类型
const router = new VueRouter({
  routes: [
    // 如果 props 是一个对象,它会被按原样设置为组件属性
    { path: '/user/:id', component: User, props: { uname: 'lisi', age: 12 } }]
})
const User = {
  props: ['uname', 'age'],
  template:< div > 用户信息:{{ uname + '---' + age}}</ > '
  }
3.3 props的值为函数类型
const router = new VueRouter({
  routes: [
    // 如果 props 是一个函数,则这个函数接收 route 对象为自己的形参
    {
      path: '/user/:id',
      component: User,
      props: route => ({ uname: 'zs', age: 20, id: route.params.id })
    }]
})
const User = {
  props: ['uname', 'age', 'id'],
  template:< div > 用户信息:{{ uname + '---' + age + '---' + id}}</div > '
  }

14.5 vue-router命名路由

1. 命名路由的配置规则
  • 为了更加方便的表示路由的路径,可以给路由规则起一个别名,即为“命名路由”。
const router = new VueRouter({
  routes: [
    {
      path: '/user/:id',
      name: 'user',
      component: User
    }]
})
  < router - link : to = "{ name: 'user', params: { id: 123 }}" > User</ >
    router.push({ name: 'user', params: { id: 123 } })

14.6 vue-router编程式导航

1. 页面导航的两种方式
  • 声明式导航:通过点击链接实现导航的方式,叫做声明式导航
  • 例如:普通网页中的 <a></a> 链接 或 vue 中的 <router-link></router-link>
  • 编程式导航:通过调用JavaScript形式的API实现导航的方式,叫做编程式导航
  • 例如:普通网页中的 location.href
2. 编程式导航基本用法
  • 常用的编程式导航 API 如下:
    • this.$router.push('hash地址')
    • this.$router.go(n)
const User = {
  template: '<div><button @click="goRegister">跳转到注册页面</button></div>',
  methods: {
    goRegister: function () {
      // 用编程的方式控制路由跳转
      this.$router.push('/register');
    }
  }
}
3. 编程式导航参数规则
  • router.push() 方法的参数规则
// 字符串(路径名称)
router.push('/home')
// 对象
router.push({ path: '/home' })
// 命名的路由(传递参数)
router.push({ name: '/user', params: { userId: 123 } })
// 带查询参数,变成 /register?uname=lisi
router.push({ path: '/register', query: { uname: 'lisi' } })

14.5 HTML5 History 模式

  • hash路由例如: http://localhost:8080/#/home
  • history路由例如: http://localhost:8080/home (以后上线需要服务器端支持, 否则找的是文件夹)
  • 利用 history.pushState API 来完成 URL 跳转而无须重新加载页面
    • 在实例化路由对象时, 传入mode选项和值修改
    • mode: ‘history’,

15. 插槽

15.1 什么是插槽

  • 插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽
  • 可以把插槽认为是组件封装期间,为用户预留的内容占位符

image.png

15.2 插槽的基础用法

  • 在封装组件时,可以通过 <slot> 元素定义插槽,从而为用户预留内容占位符。

image.png

  • 没有预留插槽的内容会被丢弃
  • 如果在封装组件时没有预留任何 <slot> 插槽,则用户提供的任何自定义内容都会被丢弃。

image.png

15.3 默认插槽

  • 封装组件时,可以为预留的 <slot> 插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何内容,则后备内容会生效。示例代码如下:

image.png

    <!-- 下面的名字叫做 default 的插槽,叫做“默认插槽” -->
    <slot name="default" info="abc">
      <!-- 后备内容 -->
      <h1>后备内容</h1>
    </slot>

15.4 具名插槽

  • 如果在封装组件时需要预留多个插槽节点,则需要为每个 <slot> 插槽指定具体的 name 名称。这种带有具体名称的插槽叫做“具名插槽”。示例代码如下:

image.png

  • 注意:没有指定 name 名称的插槽,会有隐含的名称叫做 “default”。
1. 为具名插槽提供内容
  • 在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。示例代码如下:

image.png

2. 具名插槽的简写形式
  • 跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header可以被重写为 #header

image.png

15.5 作用域插槽

  • 在封装组件的过程中,可以为预留的 <slot> 插槽绑定 props 数据,这种带有 props 数据的 <slot> 叫做“作用域插槽”。示例代码如下:

image.png

1. 使用作用域插槽
  • 可以使用 v-slot: 的形式,接收作用域插槽对外提供的数据。示例代码如下:

image.png

      <!-- 可以使用 = 来接收作用域插槽对外提供的数据 -->
      <template #author="{author, msg}">
        <h6>作者:{{ author }} -- {{ msg }}</h6>
      </template>
2. 解构插槽 Prop
  • 作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程。示例代码如下:

image.png

思维导图:https://juejin.cn/post/7078338371910631460/

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值