• Vue2、Vue3知识总结---完整版✨


    ⭐️Vue

    vue3基础入门参考文章!必看

    Vue 2

    是一套用于构建用户界面的框架

    Vue 的特性

    请添加图片描述

    • MVVM

      • MVVM 指的是 Model、View 和 ViewModel,它把每个 HTML 页面都拆分成了这三个部分
        • Model 表示当前页面渲染时所依赖的数据源。
        • View 表示当前页面所渲染的 DOM 结构。
        • ViewModel 表示 vue 的实例,它是 MVVM 的核心。
    • 数据代理

      通过vm对象来代理data对象中属性的操作(读/写)

      • 更加方便的操作data中的数据

      • 基本原理

        • 通过Object.defineProperty()把data对象中所有属性添加到vm上。

        • 为每一个添加到vm上的属性,都指定一个getter/setter。

        • 在getter/setter内部去操作(读/写)data中对应的属性。

    Vue监视数据的原理:

        1. vue会监视data中所有层次的数据。
    
        2. 如何监测对象中的数据?
    	通过setter实现监视,且要在new Vue时就传入要监测的数据。
            (1).对象中后追加的属性,Vue默认不做响应式处理
            (2).如需给后添加的属性做响应式,请使用如下API:
            Vue.set(target,propertyName/index,value) 或 
            vm.$set(target,propertyName/index,value)
    
    	3. 如何监测数组中的数据?
    		通过包裹数组更新元素的方法实现,本质就是做了两件事:
                (1).调用原生对应的方法对数组进行更新。
                (2).重新解析模板,进而更新页面。
    
    	4.在Vue修改数组中的某个元素一定要用如下方法:
    		1 使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
    		2 Vue.set() 或 vm.$set()
    				
    		特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Vue 的基本使用

    • 使用步骤

      • 1 导入 vue.js 的script 脚本文件
      • 2 在页面中声明一个将被 Vue 所控制的 DOM 区域
      • 3 创建 vm 实例对象
      <!-- 希望 Vue 能够控制下面的这个 div,帮我们在把数据填充到 div 内部 -->
        <div id="app">{{ username }}</div>
      
        <!-- 1. 导入 Vue 的库文件,在 window 全局就有了 Vue 这个构造函数 -->
        <script src="./lib/vue-2.6.12.js"></script>
        <!-- 2. 创建 Vue 的实例对象 -->
        <script>
          // 创建 Vue 的实例对象
          const vm = new Vue({
            // el 属性是固定的写法,表示当前 vm 实例要控制页面上的哪个区域,接收的值是一个选择器
            el: '#app',
            // data 对象就是要渲染到页面上的数据
            data: {
              username: 'zhangsan'
            }
          })
        </script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17

    请添加图片描述

    指令

    指令 是 Vue 为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构

    按照不同用途可分为:

    1 内容渲染指令

    • v-text

      • 示例:

        性别:

      • ❗️v-text 指令会覆盖元素内默认的值
    • ⭐️{{ }}

      • 性别:{{ gender }}

      • 不会覆盖元素内默认的值
    • v-html

      • 把包含 HTML 标签的字符串渲染为页面的 HTML 元素

      • ❗️v-html有安全性问题

        • (1).在网站上动态渲染任意HTML是非常危险的,容易导致 XSS 攻击。

        • (2).一定要在可信的内容上使用v-html,不要用在用户提交的内容上!(和eval()有点像)

    • v-cloak

      • 1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
      • 2.使用css(display:'none')配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
    • v-once

      • 1.v-once所在节点在初次动态渲染后,就视为静态内容了。
      • 2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
    • v-pre

      • 1.跳过其所在节点的编译过程。
      • 2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

    2 属性绑定

    • v-bind:

      • v-bind: 指令可以简写为 :

      • 动态绑定 class / style / checked

        • :checked="isChecked"

          • isChekced是 Boolean值
        • 字符串:

          • 适用于:类名不确定,要动态获取。
          • :class="classes"
            • classes是一个计算属性
        • 对象语法:

          • 要绑定多个样式,个数确定,名字也确定,但不确定用不用

          • :class="{active:isActive}"

          • :class="{active:isActive,line:isLine}"

          • class="title":class="{active:isActive,line:isLine}"

        • 数组语法:

          • 要绑定多个样式,个数不确定,名字也不确定。
          • :style='[styleobj,overridingStyles]'

      使用 JavaScript 表达式 的运算

      请添加图片描述

    3 事件绑定

    • v-on :简写形式:@

      • eg: @click=‘addCount’ @keyup=‘count += 1’
    • 需要在 methods 节点中进行声明
      在这里插入图片描述

    • 事件参数对象

      • $(event) 指原生的事件参数对象 event

      • 绑定事件并传参

    • 事件修饰符

      事件修饰符说明
      .prevent阻止默认行为(eg:阻止 a 链接的跳转、阻止表单的提交等)
      .stop阻止事件冒泡
      .capture以捕获模式触发当前的事件处理函数
      .once绑定的事件只触发一次
      .self只有在 event.target 是当前元素自身时触发事件处理函数
    • 按键修饰符

      • .enter
      • .delete
      • .esc
      • .space
      • .up .down .left .right
      • tab 换行 (必须配合 keydown去使用)
    • 可以执行少量代码 count++

    • 可以写函数传参(可以获取事件对象,没写参数默认有,写参数要 (a,$event)

      • 给调用函数+个()eg:@change="handelClick()"
      • 如果只有一个 e 不加 ()
      • e.target.value/checkded

    4 双向绑定

    • v-model

      • 实现表单数据的双向绑定

      • 用于获取表单(输入类)的数据

      • 场景

        • 表单(value / checked)、全选(状态在 computed )反选(状态在 data )
      • 收集表单数据:
            若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
        
            若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
        
            若:<input type="checkbox"/>
            1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
            
            2.配置input的value属性:
              (1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
              
              (2)v-model的初始值是数组,那么收集的的就是value组成的数组(多选)
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
      • v-model 修饰符

        修饰符作用示例
        .number自动把用户输入的值转为数值类型
        .trim自动过滤用户输入 的首尾空白字符
        .lazy在“change”时而非“input”时更新

    5 条件渲染

    • 条件渲染指令用来辅助开发者按需控制 DOM 的显示与隐藏

      • v-if

        • 这是被 v-if 控制的元素

        • 会动态地创建或移除 DOM 元素

          • v-elsev-else-if=“ ”
          • 必须相邻
        • 只能在与 v-if 平级的时候使用

          优秀
          良好
          一般
        • 移除时 dom 不存在

      • v-show

      • 这是被 v-show 控制的元素

        • 会动态为元素添加或移除 style=“display: none;” 样式
        • 移除时 dom 存在
      v-ifv-show
      动态地创建或移除 DOM 元素动态为元素添加或移除 style="display: none;"样式
      支持多条件显示不支持多条件显示
      有更高的开销有更高的初始渲染开销
      使用场景:切换频率较低、判断条件较多的场景使用场景:非常频繁地切换

    6 列表渲染

    • v-for

      • 基于一个数组来循环渲染一个列表结构
      • 需要使用 item in items 形式的特殊语法
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ index }}</td>
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
      </tr>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 1 用于 循环 数组 (item,index) in array
      • 2 用于循环 对象 (item,key) in obj
      • 3 用于循环 数字 item in num
      • 使用 key 维护列表的状态
        • Vue 复用已存在的DOM元素提升渲染性能 但导致有状态的列表无法被正确更新
        • key 注意事项
          • key 的值只能是字符串或数字类型
          • key 的值必须 具有唯一性
          • 建议把数据项的 id 属性值作为 key 的值
          • 使用 index 的值当做 key 的值没有意义( index 不具唯一性)
          • 建议使用 v-for 指令时要指定 key 的值(既提升性能,又防止列表状态紊乱)
      • label 的 for 属性
        • :for="'cb' + item.id" input里面 :id="'cb' + item.id"

    过滤器

    过滤器(Filters)是 vue 为开发者提供的功能,常用于文本的格式化。本质是 js 函数

    • 过滤器放在 js 表达式的尾部 由“管道符”进行调用

      • 插值表达式
        • message 的值是:{{ message | capi }}

        • 不能给属性用,直接“ ”
      • v-bind 属性绑定
    • 定义过滤器

      • 在创建 vue 实例期间,可以在 filters 节点中定义过滤器

        filters: {
            // 注意:过滤器函数形参中的 val,永远都是“管道符”前面的那个值
            capi(val) {
              // 字符串有 charAt 方法,这个方法接收索引值,表示从字符串中把索引对应的字符,获取出来
              // val.charAt(0)
              const first = val.charAt(0).toUpperCase()
              // 字符串的 slice 方法,可以截取字符串,从指定索引往后截取
              const other = val.slice(1)
              // 强调:过滤器中,一定要有一个返回值
              return first + other
            }
          }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
      • 私有过滤器

        在 filters 节点下定义的过滤器,称为“私有过滤器”,因为它只能在当前 vm 实例所控制的 el 区域内使用。

      • 全局过滤器

        // 使用 Vue.filter() 定义全局过滤器
            Vue.filter('capi', function (str) {
              const first = str.charAt(0).toUpperCase()
              const other = str.slice(1)
              return first + other + '~~~'
            })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
    • 连续调用多个过滤器

      • message 的值是:{{ message | capi | maxLength }}

    • 过滤器传参

      • 本质是 js 函数

        <p>{{ message | filterA(arg1,arg2)}</p>
        
        Vue.filter('filterA',(mesg,arg1,arg2)=>{})
        
        • 1
        • 2
        • 3
    • 兼容性

      • 仅在 Vue1、2中受支持
      • vue3 不支持
        • 官方建议使用 计算属性方法 代替过滤器功能
        • 参考

    侦听器

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

    当被监视的属性变化时, 回调函数自动调用, 进行相关操作

    • 1 在 watch 节点进行声明
    const vm = new Vue({
      el: '#app',
      data: {
        username: 'admin'
      },
      // 所有的侦听器,都应该被定义到 watch 节点下
      watch: {
        // 侦听器本质上是一个函数,要监视哪个数据的变化,就把数据名作为方法名即可
          
        // 新值在前,旧值在后
        username(newVal) {
          if (newVal === '') return
          // 1. 调用 jQuery 中的 Ajax 发起请求,判断 newVal 是否被占用!!!
          $.get('https://www.escook.cn/api/finduser/' + newVal, function (result) {
            console.log(result)
          })
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 2 使用 watch 检测用户名是否可用

      监听 username 值的变化,并使用 axios 发起 Ajax 请求,检测当前输入的用户名是否可用:

      watch: {
      // 监听 username 值的变化
          async username(newVal) {
              if (newVal === '') return
              // 使用 axios 发起请求,判断用户名是否可用
              const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
      	} 
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 3 immediate选项

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

      watch: {
         // 让被监听的对象指向一个 配置对象
      username: {
      // handler 是固定写法,表示当 username 的值变化时,自动调用 handler 处理函数
          handler: async function (newVal) {
              if (newVal === '') return
              const { data: res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal)
              console.log(res)
      },
      // 表示页面初次渲染好之后,就立即触发当前的 watch 侦听器
      immediate: true
      } }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    • 4 deep 选项

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

      • 在上面的基础上加一个 deep:true
    • 5 监听对象单个属性的变化

      watch:{
          info: {
            handler(newVal) {
              console.log(newVal)
            },
            deep:true,
          }
          // 如果要侦听的是 子属性 的变换,则必须包裹一层单引号
          'info.username'(newVal) {
            console.log(newVal)
          }
          // 配置对象
          'info.username':{
             async handler(newVal){
                const { data:res } = await axios.get('https://www.escook.cn/api/finduser/' + newVal.username)
                console.log(res)
              }
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

    监视的属性必须存在,才能进行监视!!

    • 应用场景

      • 本地存储

        subjectList() { // 要侦听的属性
            localStorage.setItem('scoreMsg', JSON.stringify(this.subjectList))
            }
        
        • 1
        • 2
        • 3
      • 当监听 对象数组 时,数组的长度变化时,不用 deep 也可以,但是监听不到对象内部的 变化

      • 数据变化时,发起 ajax 请求

    计算属性

    计算属性指的是通过一系列运算之后,最终得到一个属性值

    • 个动态计算出来的属性值可以被模板结构或 methods 方法使用。

      <div id="app">
          <!-- 专门用户呈现颜色的 div 盒子 -->
          <!-- 在属性身上,: 代表  v-bind: 属性绑定 -->
          <!-- :style 代表动态绑定一个样式对象,它的值是一个 {  } 样式对象 -->
          <!-- 当前的样式对象中,只包含 backgroundColor 背景颜色 -->
          <div class="box" :style="{ backgroundColor: rgb }">
            {{ rgb }}
          </div>
          <button @click="show">按钮</button>
      </div>
      
        <script>
          // 创建 Vue 实例,得到 ViewModel
          var vm = new Vue({
            el: '#app',
            data: {
              // 红色
              r: 0,
              // 绿色
              g: 0,
              // 蓝色
              b: 0
            },
            methods: {
              // 点击按钮,在终端显示最新的颜色
              show() {
                console.log(this.rgb)
              }
            },
            // 所有的计算属性,都要定义到 computed 节点之下
            // 计算属性在定义的时候,要定义成“方法格式”
            computed: {
              // rgb 作为一个计算属性,被定义成了方法格式,
              // 最终,在这个方法中,要返回一个生成好的 rgb(x,x,x) 的字符串
              rgb() {
                return `rgb(${this.r}, ${this.g}, ${this.b})`
              }
            }
          });
      
          console.log(vm)
        </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
      • 所有的计算属性,都要定义到 computed 节点之下
      • 计算属性在定义的时候,要定义成“方法格式”
    • 计算属性的特点

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

      • 代码复用
      • data变化,计算属性也变化
    • 应用场景

      • 反选
        • return this.list.every(item => item.checked === true)
      • total
        • return this.subjectList.reduce((pre, current) => (pre += current.score), 0)
    全选:v-model="allChecked" 反选:computed
    
    computed: {
        allChecked: {
          get() {
            return this.list.every(item => item.checked === true)
          },
          set(allChecked) {
            this.checked = !allChecked
            this.list.forEach(item => (item.checked = allChecked))
          }
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    计算属性:
        1.定义:要用的属性不存在,要通过`已有属性`计算得来。
        
        2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
    
        3.get函数什么时候执行?
            (1).初次读取时会执行一次。
            (2).当依赖的数据发生改变时会被再次调用。
    
        4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
        
        5.备注:
            1.计算属性最终会出现在vm上,直接读取使用即可。
            2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    计算属性 vs 侦听器

    1 计算属性侧重于监听多个值的变化,最终计算并返回一个新值

    2 侦听器侧重于监听单个数据的变化,最终执行特定的业务处理,不需要有任何返回值

    3 computed能完成的功能,watch都可以完成。watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。

    axios

    axios 是一个专注于网络请求的库

    • 调用 axios 方法得到的返回值是 Promise对象

    • const result = axios({
          method:'GET',
          url:'',
        	// URL 中的查询参数 GET
          // params:{},
          // 请求体参数 POST
          // data:{}
      })
      result.then(res=>{
          console.log(res.data)
      })
      
      $('#btnPost').on('click',async ()=>{
          const { data:res } = await axios({
              method:'POST',
              url:'',
              data:{
                  name:'zs',
                  age:20
          }
      }) // 返回的是数据对象 可以解构单独拿出 data 把 data 重命名为 res
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

    在这里插入图片描述

    如果调用某个方法的返回值是 Promise 实例,则前面可以添加 await

    await 只能在被 async “修饰”的方法中

    用 jQuery 可以发起 $.ajax() $.get() $.post() 请求

    axios:axios() axios.get() axios.post() axios.delete() axios.put() axios.patch()

    axios.get()

    $('#btnPost').on('click',async ()=>{
        const { data:res } = await axios.get('url',{params:{id:1}})
    })
    
    • 1
    • 2
    • 3

    axios.post()

    $('#btnPost').on('click',async ()=>{
        const { data:res } = await axios.post('url',{name:'zs',gender:'女'}) // axios.post()里面的请求体直接写数据对象
    })
    
    • 1
    • 2
    • 3

    组件中发起axios 请求,不用每个组件都要导入 axios,在 main.js 导入,变成 Vue内置的成员

    // main.js
    import axios from 'axios'
    
    // 配置请求根路径
    axios.defaults.baseURL = 'http://www.itcbc.com:3006'
    
    // 把 axios 挂载到 Vue.prototype上,供每个组件的实例直接使用
    // 缺点: 不利于接口的 复用
    Vue.propotype.$http = axios
    
    // 组件中
    methods:{
        async getBooks(){
            const {data : res} = await this.$http.get('http://www.itcbc.com:3006/api/getbooks')
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    $mount方法

    const vm = new Vue({
      data: {
        username: 'admin'
      }
    })
    
    vm.$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    vue/cli

    vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程

    下载: npm i -g @vue/cli 查找安装: vue -V

    1. 在指定目录的 终端下 创建指定名称的项目

      • vue create demo-first

      • 项目名称不能有空格、中文、大写字母
        在这里插入图片描述

      • 创建冻结 按 ctrl + c

      • 创建成功 cd 项目名称 npm run serve 不要关掉终端

    2. vue 项目中 src 目录的构成

    • assets 放:图片、css 样式等静态资源

    • components :放封装好的 组件

    • main.js :是项目的入口文件,整个项目的运行,要先执行 main.js

    ![在这里插入图片描述](https://img-blog.csdnimg.cn/721187076eeb40748414a0f0fa998f01.png#pic_center)
    
    • 1
    • app.vue:是项目的根组件(render渲染的组件就是根组件)
    1. vue 项目运行流程

      • 通过 main.js 把 App.vue 渲染到 HTML 页面

    单页面应用程序

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

    vue组件

    组件是对 UI 结构的复用

    组件化开发

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

    组件的后缀名是 .vue

    一个重要的内置关系

    • VueComponent.prototype.proto === Vue.prototype
    为什么要有这个关系
    • 让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
    • this.$refs.xx(ref=xx).属性/方法()

    定义组件

    组成部分:
    • 1 template -> 组件的模板结构(必须包含

      • template 中只能包含唯一的根节点
    • 2 script -> 组件的 JavaScript 行为

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

    new Vue(options)配置中: data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

    使用组件

    • 1 使用 import 语法导入需要的组件
      • @ 表示定位到 src
      • import MyCount from 'xxx'
    • 2 使用 components 节点注册组件
    • 3 以标签的形式使用刚才注册的组件
    组件间的父子关系
    • 组件封装之后,彼此之间是相互独立的,不存在父子关系
    • 在使用组件的时候,根据彼此的嵌套关系构成 父子、兄弟关系
    私有组件
    • 使用 components 注册的是 私有组件
    • 在组件 A 的 components 节点下,注册了组件 F。 则组件 F 只能用在组件 A 中;不能被用在组件 C 中。
    • component:{ MyCount }
    • ⭐️component:{ 'my-count', MyCount }
    注册全局组件
    • 在 vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。
      • 1 import
      • 2 Vue.component('MyCount',MyCount)

    组件的 name 会显示在 devtools 上

    组件的 props

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

    exports default{
    	props:['自定义属性A''自定义属性B''...'],
        data(){
            return {}
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • props 是只读的

      • 修改:把 props 的值 转存 到 data 中,data 中的数据都是可读写的

      • 不要直接在 子组件里修改 props 的值 (会报错,父组件没跟着变)

        props:['init'],
        data(){
            return{
                count:this.init
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
    • props 的 default 默认值

      • props:{ init: { default: 0 }}

      • 用户没传 init 的值时,default 的值生效

      • 对象或数组默认值必须从一个工厂函数获取

        default:function() {
            return {message:'hello'}
        }
        
        • 1
        • 2
        • 3
    • type 值类型

      • eg:type: Number
      • :init="9" v-bind: 加上 js 的数字
      • 写在 props 里面
      • props:{name:String}
    • required 必填项

      • required: true

    使用:

    组件之间的样式冲突问题

    默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

    • 根本原因

      • 1 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的
      • 2 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素
    • 解决

      • 1 为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器来控制样式的作用域

        <style> .container[data-v-0001]{ border: 1px solid red;} </style>
        
        • 1
      • 2 style 的 scoped 属性

        • 防止组件之间的样式冲突问题
        • 则当前组件的样式对其子组件是不生效的
      • 3 /deep/ 样式穿透

        • 让某些样式对子组件生效
    • 当使用第三方组件库的时候,如果有修改第三方组件默认样式的需求,需要用到 /deep/

      在这里插入图片描述

    组件的生命周期

    生命周期

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

    生命周期函数

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

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

    • beforeCreate()

      • 创建阶段的第一个生命周期函数
      • 组件的 props/data/methods 尚未被创建,都处于 不可用 状态
    • ⭐️created()

      • 组件的 props/data/methods 已创建好,都处于 可用 状态,但是组件的模板结构未生成
      • 在里面调用 methods 方法,请求服务器的数据,并且,把请求到的数据,转存到 data 中,供 template 使用
      • 有些bus.$on()写在 created 里面
    • beforeMount

      • 浏览器还没当前组件的 DOM结构
    • ⭐️mounted

      • 已渲染 HTML,第一次取到 DOM 结构
      • 启动定时器绑定自定义事件订阅消息等【初始化操作】
    • beforeUpdate

      • 将要 根据变化、更新后的数据,重新渲染组件的模板结构
    • ⭐️updated

      • 已根据最新的数据,完成了组件 DOM 结构 的重新渲染
      • 当数据变化之后,为了能够操作到最新的 DOM 结构,必须把代码写到 updated 生命周期函数中
      • 但是一般不在这里做什么,因为一个属性变化就会触发 updated
    • beforeDestroy

      • 尚未销毁组件,还处于 正常工作状态
      • 清除定时器解绑自定义事件取消订阅消息等【收尾工作】
    • destroyed

      • 组件已被销毁,DOM 结构已被完全移除
      • 销毁后自定义事件会失效,但原生DOM事件依然有效。
      • 一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
        在这里插入图片描述
    ⭐️组件之间的数据共享

    1 父组件向子组件共享数据

    • 需要使用自定义属性

    在这里插入图片描述

    • 也就是 使用自定义属性的方法

    2 子组件向父组件共享数据

    • 使用自定义事件(以传参的形式 去共享数据)
    • 父:函数
      • 函数接收数据
    • 子:props:[‘函数名称’]
      • 调用函数,传递参数数据

    在这里插入图片描述

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

    • 在 vue2 中,兄弟组件之间的数据共享的方案是 EventBus

    • EventBus 的使用步骤

      • 1 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象
      • 2 在数据发送方,调用 bus.**$emit(**'事件名称', 要发送的数据) 方法触发自定义事件
      • 3 在数据接收方,调用 bus.**$on**('事件名称', 事件处理函数) 方法注册一个自定义事件
      • bus.$off('xxx')解绑

    在这里插入图片描述

    4 ⭐️全局事件总线:任意组件间通信

    • main.js

      • 在vue 实例beforeCreate(){ Vue.prototype.$bus = this}
    • 发送方

      • this.$bus.$emit('deleteTodo', 参数)
    • 接收方

       mounted() {
       this.$bus.$on('checkTodo', this.checkTodo)
      this.$bus.$on('deleteTodo', this.deleteTodo)
        },
            
        beforeDestroy() {
          this.$bus.$off('checkTodo')
          this.$bus.$off('deleteTodo')
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

    5 消息订阅与发布 实现任意组件间通讯

    使用步骤:

    1. 安装pubsub:npm i pubsub-js

    2. 引入: import pubsub from 'pubsub-js'

    3. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

      methods(){
        demo(data){......} =》或者写在回调函数里
      }
      ......
      mounted() {
        this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息 (msgName,data)=>{...} 写箭头函数
      }
      beforeDestroy(){ pubsub.unsunscribe(this.pid)}    
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    4. 提供数据:pubsub.publish('xxx',数据)

    5. 最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

    ref 引用

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

    每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。

    默认情况下, 组件的 this.$refs 指向一个空对象。

    • 使用 ref 引用 DOM 元素

    在这里插入图片描述

    • 使用 ref 引用组件实例

    在这里插入图片描述

    • ref=' ' 写在 组件使用标签上

    • 引用到组件的实例后,就可以调用组件上的 methods 方法

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

      通过布尔值 inputVisible 来控制组件中的文本框与按钮的按需切换。

      在这里插入图片描述

    • 让文本框自动获得焦点

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

      在这里插入图片描述

    • this.$nextTick(cb) 方法

      组件的 $nextTick(cb) 方法,会把 cb 回调推迟到下一个 DOM 更新周期之后执行。

      即等组件的 DOM 更新完成之后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。
      在这里插入图片描述

    @ 从 src 源目录从外往里找

    ❗️一个重要的内置关系:

    VueComponent.prototype.__proto__ === Vue.prototype

    让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

    动态组件

    动态组件指的是动态切换组件的显示与隐藏。

    动态组件的渲染

    vue 提供了一个内置的 组件,专门用来实现动态组件的渲染。

    data(){ // 函数 避免组件被复用时,数据存在引用关系。
        return {comName:'Left'}
    }
    
    <componet :is="comName"></componet>
    
    <button @click="comName = 'Left'">切换 Left 组件</button>
    <button @click="comName = 'Right'">切换 Right 组件</button>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    使用 内置的 keep-alive 保持状态

    解决默认情况下,切换动态组件时无法保持组件的状态的问题。

    <keep-alive>
    	<component :is="comName"></component>
    </keep-alive>
    
    • 1
    • 2
    • 3
    keep-alive 对应的生命周期函数
    • 当组件被缓存时,会自动触发组件的 deactivated 生命周期函数。
    • 当组件被激活时,会自动触发组件的 activated 生命周期函数。
      • 当组件第一次被创建是,即会触发created 也会触发 actived
      • 当组件被激活,只会触发 actived,不再触发 created,因为组件没有被重新创建
    keep-alive 的 include 属性

    include 属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间使用英文的逗号分隔:

    • 与 include 相对的是 exclude(指定哪些组件不需要被缓存)只能二选一
    <keep-alive include="MyLeft,MyRight">
        <component :is="comName"></component>
    </keep-alive>
    
    • 1
    • 2
    • 3

    组件的name属性:

    当提供了 name 属性之后,组件的名称,就是 name 属性的值

    export default{
        name:'MyRight'
    }
    
    • 1
    • 2
    • 3

    对比:

    • name
      • 1 调试的时候 出现的 组件名称
      • 2 与 结合 指定被缓存与不被缓存
    • 注册名称
      • 应用场景:以标签的形式,把注册好的组件,渲染和使用到页面结构之中

    mixin(混入)

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

    独立的 js 文件

    使用:

    1 定义混合

    export const xxx = {
        data(){...}
    	methods(){...}
    	...
    }
    export const yyy = {
    data(){...}
    methods(){...}
    ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2 使用混合

    • 全局混入
      • 在 main.js 中 Vue.mixin(xxx)
    • 局部混入 // App.vue or 某一组件中
      • import {xxx,yyy} from '/mixin'
      • mixins:[xxx,yyy]

    插件

    独立的 js 文件

    // 1 定义插件 plugins.js
    export default {
        install(Vue,x,y,z)
        // 1. 添加全局过滤器
        Vue.filter('mySlice',function(value){
            return value.sclice(0,4)
        })
        
        // 2. 添加全局指令
        Vue.directive('fbind',{bind(el,binding){ el.value = binding.value},
    	insert(el,binding){el.focus()},update(el,binding){el.value = 		binding.value}
    	})
    
        // 3. 配置全局混入(合)
        Vue.mixin({data(){ return {x:100,y:200 }}})
    
        // 4. 添加实例方法
        Vue.prototype.$myMethod = function () {...}
        Vue.prototype.$myProperty = xxxx
                                               
        // 5. 添加全局组件
        Vue.component('myButton',{})                                       
    }
    
    // 2 引入插件 main.js
    import myBtn from '@/plugin/plugins.js'
    // 3 使用自定义插件
    <my-button/>
    
    • 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

    插槽

    插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。

    可以把插槽认为是组件封装期间,为用户预留的内容的占位符。

    在这里插入图片描述

    基础用法: