• Vue3 学习总结笔记 (十三)


    1. Vue3 简介


    Vue3 代号:One Piece(海贼王) 。

    在这里插入图片描述


    vue3 比 vue2 的好处:

    • 打包大小减少,渲染速度更快,内存减少。

    源码升级:

    • 使用Proxy代替ObjectDefineProperty实现响应式。
    • vue3可以更好的支持TypeScript。

    新的特性:

    2. 创建Vue3项目工程

    2.1 使用Vue-cli创建


    前提:确保@vue/cli的版本在4.5.0之前上!

    # 查看版本命令
    vue -V  或者 vue --version
    # 创建一个名为vue3_test的项目
    vue create vue3_test
    # 注意中间要选择Vue3版本!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    在这里插入图片描述

    2.2 使用Vite创建Vue3工程


    Vite是新一代的前端开发构建工具。和Webpack功能一样。

    官方地址:https://vitejs.cn/

    vite的优点:

    • 开发环境中,无需打包操作,可快速的冷启动。
    • 轻量快速的热量载(HMR)。
    • 真正的按需编辑,不再等待整个应用编译完成。

    在这里插入图片描述
    图上前者是先将所有的模块准备好,在搭建好server服务器。后者是先准备好服务器,之后通过请求去找对应的模块,正好与前面反着,这样更加快一点。


    命令如下:

    # 创建工程
    npm init vite-app <project-name>
    # 进入工程目录
    cd <project-name>
    # 安装依赖
    npm install
    # 运行
    npm run dev
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3. Vue3 之 分析工程结构


    main.js文件结构如下:

    //引入的不再是Vue构造函数了,而引用的是createApp就是创建一个应用的工厂函数。
    import { createApp } from 'vue'
    import App from './App.vue'
    
    //创建应用实例对象-app(类似于之前vue2中的vm,但app比vm更轻)
    const app = createApp(App)
    console.log('@@@',App)
    
    //mount就是挂载,与vue3不同的是没有了$符号。
    app.mount('#app')
    
    setTimeout(()=>{
        //调用unmount可以卸载app应用
        app.unmount('#app')
    },3000)
    
    // 注意vue3构想的项目,并不支持vue2的写法!!!
    // vue2 的写法,通过el或者$mount来指定容器,通过render来渲染。
    // const vm = new Vue({
    //     // el:'#app'
    //     render:(h)=> h(App)
    // })
    //
    // vm.$mount('#app')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    createApp(App)的结构如下:
    在这里插入图片描述

    组件里面,模板结构可以没有根标签了。
    在这里插入图片描述

    3. Vue3 之 安装开发者工具


    Vue的dev-tools安装包:https://gitee.com/it-sherlock/develop-common-parameters/tree/master/%E5%89%8D%E7%AB%AF/Vue/dev-tools
    在这里插入图片描述

    4. Vue3 之 setup


    Composition API:组合式API

    setup是Vue3的新的配置项。

    setup是所有Composition API(组合API)的表演舞台。

    组件中所用到的:数据,方法等等,均要配置在setup中!!! 而Vue2,数据要配置在data配置项中,方法配置在methods中。


    setup可以直接返回数据和方法:
    在这里插入图片描述

    setup还可以返回渲染函数:
    在这里插入图片描述


    在vue3项目中,可以配置vue2的data,methods的写法,但是非常不建议!!

    vue3的setup是不能够访问到vue2的data,methods等一些数据和方法的!!

    总结:
    在这里插入图片描述

    注意:setup不能使用async修饰。如果加上了,async会将其的返回值包裹为一个promise对象,这样setup的返回值就不是一个单纯的对象了。

    5. Vue3 之 ref函数

    5.1 ref函数 处理基本数据类型


    前提:先引入ref函数,从vue中!

    import {ref} from 'vue'
    
    • 1

    vue2中的ref是作为一个属性,类似于id选择器,打标识用的。

    在vue3中,多了一个ref函数,ref函数可以让定义的数据具有响应式。直接在setup定义并且返回的变量,是不具有响应式的,值变化页面并不会变化!

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    对于基本数据类型而言,ref函数用到了ObjectDefineProperty方法来实现的,走的是get和set方法来实现响应式。

    5.2 ref函数 处理对象类型


    ref函数,对于处理对象数据类型,是用的ES6的Proxy代理对象。

    对于对象,直接使用 对象.value.属性名 来触发响应式就可以。

    在这里插入图片描述

    总结:
    在这里插入图片描述

    6. Vue3 之 reactive函数


    前提:也是在vue中,引入reactive函数

    import {reactive} from 'vue'
    
    • 1

    不要用reactive函数来处理基本数据类型,reactive专门用来处理对象类型!!

    ref函数也能够处理对象类型,原因就是它在处理对象的时候底层也去使用了reactive函数。

    reactive的底层不再通过ObjectDefineProperty函数达到响应式了。而是通过Proxy实现。
    在这里插入图片描述


    reactive函数可以支持深层次的对象数据的响应式,也支持数组数据的响应式。
    在这里插入图片描述

    小知识点:

    • vue2中通过索引修改的数组中的数据是不会触发响应式的,一般在vue2通过$set来触发数据数据的响应式索引。
    • 当然,在vue2中,通过索引项内的某个属性是可以触发响应式的!例如:vm.list[3].a = 456。
    • vue3就弥补了vue2的这个缺点,即便是通过索引赋值也能够触发响应式!

    reactive函数使用:

    • 一般形式是:const 代理对象 = reactive(源对象) 就是将源对象加工成为代理对象(Proxy的实例对象,简称proxy对象)。
      在这里插入图片描述

    reactive的内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作。

    7. Vue3 之 与vue2进行比较

    7.1 Vue2 响应式原理以及注意事项


    vue2的数组push,做了两件事,一个是往数组中添加数据,另一个是更新页面数据。

    因为Vue2使用的是ObjectDefineProperty方法中的get和set方法,对于获取就用get,对于修改就用set,然而对于添加和删除却是无可奈何的!!

    vue2对象添加一个属性:

    • 新增属性不能直接通过 person.sex = '女’的方式来添加,这样不会触发响应式!
      在这里插入图片描述
      vue2删除一个属性:
    • 直接通过原生的 delete this.person.name 删除name是不会触发响应式的!
      在这里插入图片描述

    vue2数组的操作:
    在这里插入图片描述

    总结:
    在这里插入图片描述

    7.2 Vue3 的响应式原理

    7.2.1 Proxy对象


    有了reactive,vue3就弥补了上面vue2不能直接添加删除,数组索引项不能直接赋值的缺点!
    在这里插入图片描述

    还是那句话,Object.defineProperty能检测get获取和set设置,但是不能够检测到删除和添加属性。所以还是有小毛病的!
    在这里插入图片描述


    ES6的 Proxy对象:

    • Proxy对象在window上面,通过window.proxy来查看。
    //源数据
    let person = {
        name:'张三',
        age:18
    }
    const p = new Proxy(person,{})
    console.log(p)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    //Vue3的响应式,通过配置第二个参数handler对象来达到响应式
    const p = new Proxy(person,{
        //读取p的某个属性时调用
        get(target, propName, receiver) {
            console.log(`有人读取了p身上的${propName}属性`)
            console.log(target)
            console.log(propName)
            return target[propName]
        },
        //修改p的某个属性时调用 和 新增p的某个属性时调用
        set(target, propName, value, receiver) {
            console.log(`有人修改了p身上的${propName}属性,我要更新页面了!`)
            console.log(target)
            console.log(propName)
            console.log(value)
            target[propName] = value
        },
        //删除p的某个属性时调用
        deleteProperty(target, propName) {
            console.log(`有人删除了p身上的${propName}属性,我要更新页面了!`)
            //delete返回的是一个布尔值,同时deleteProperty也要返回一个布尔值!!
            let boolean = delete target[propName]
            return boolean
        }
    })
    
    • 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

    7.2.2 Reflect对象


    Reflect也是可以对对象的属性进行获取,修改,新增,删除操作。
    在这里插入图片描述
    在这里插入图片描述


    Object.defineProperty与 Reflect的对比:
    在这里插入图片描述

    Reflect相对比较健壮!!


    vue3底层的对对象的增删改查,并不会直接使用target操作,而是通过Reflect函数进行操作如下:

    //Vue3的响应式,通过配置第二个参数handler对象来达到响应式
    const p = new Proxy(person,{
        //读取p的某个属性时调用
        get(target, propName, receiver) {
            console.log(`有人读取了p身上的${propName}属性`)
            console.log(target)
            console.log(propName)
            return Reflect.get(target,propName)
        },
        //修改p的某个属性时调用 和 新增p的某个属性时调用
        set(target, propName, value, receiver) {
            console.log(`有人修改了p身上的${propName}属性,我要更新页面了!`)
            console.log(target)
            console.log(propName)
            console.log(value)
            Reflect.set(target,propName,value)
        },
        //删除p的某个属性时调用
        deleteProperty(target, propName) {
            console.log(`有人删除了p身上的${propName}属性,我要更新页面了!`)
            //delete返回的是一个布尔值,同时deleteProperty也要返回一个布尔值!!
            let boolean = Reflect.deleteProperty(target,propName)
            return boolean
        }
    })
    
    • 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

    总结:
    在这里插入图片描述

    8. reactive函数 和 ref函数 有什么区别


    在这里插入图片描述

    9. 重点注意事项

    9.2 回忆Vue2的几个组件属性


    $attrs属性的作用:
    在这里插入图片描述

    $slot的作用:

    • 最终将虚拟dom转为真实dom。
      在这里插入图片描述
    • 一般都会使用template标签加slot属性指定slot名字,这样就能指定安放标签。
    • 指定slot名字两种写法:slot=“xxx” 或 v-slot:xxx 。
      在这里插入图片描述
      在这里插入图片描述

    9.3 Vue3 setup的两个注意点


    setup的执行时机:

    • 在beforeCreate之前执行一次,this是undefined。
      在这里插入图片描述

    setup的props参数使用:

    • 注意:vue3父组件传过来的属性也要将其放到props配置项里面!
      在这里插入图片描述

    setup的第二个参数context(上下文):

    • context.attrs的作用:
      在这里插入图片描述

    • context.emit 和 emits配置项的使用:
      在这里插入图片描述

    • context.slots的使用:
      在这里插入图片描述


    总结:
    在这里插入图片描述

    10. Vue3 之 Computed 计算属性


    在setup配置项里面,是肯定不会用this的,因为setup在beforeCreate之前会自动执行,打印过this是undefined!

    vue2形式的computed也是可以在vue3的项目中使用的,对应的this自然就是vue对象。

    vue3将computed变成了一个组合式api!
    在这里插入图片描述

    vue3的写法如下:

    • 记得导入computed的api。
    import {computed} from 'vue'
    
    setup(){
      let person = reactive({
        firstName: '张',
        lastName: '三',
        age: 18,
      })
    
      //计算属性 简写形式只考虑计算属性读,没有考虑计算属性的改
      // person.fullName = computed(()=>{
      //   return person.firstName + '-' + person.lastName
      // })
    
      //计算属性 完整写法(读写)
      person.fullName = computed({
        get(){
          return person.firstName + '-' + person.lastName
        },
        set(value){
          const nameArr = value.split('-')
          person.firstName = nameArr[0]
          person.lastName = nameArr[1]
        }
      })
    
      return {
        person
      }
     }
    
    • 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

    总结:
    在这里插入图片描述

    11. Vue3 之 watch属性

    11.1 Vue2的watch使用


    Vue2的watch使用:

    watch:{
      //vue2的监听简易写法:直接通过 数据对象名定义函数来监听
      // sum(newValue,oldValue){
      //   console.log('sum的值变化了',newValue,oldValue)
      // },
      //vue2监听完整写法:
      sum:{
        immediate:true, // 配置立即监听属性,一进来就先执行一次。
        deep:true, // 深度监视属性
        handler(newValue,oldValue){
          console.log('sum的值变化了',newValue,oldValue)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    11.2 Vue3 watch监听ref函数定义的数据


    watch监听ref函数如下:

    <template>
      <h2>当前求和为:{{sum}}</h2>
      <button @click="sum++">点我+1</button>
      <h2>当前的信息为:{{msg}}</h2>
      <button @click="msg += '!'">修改信息</button>
    </template>
    
    <script>
    import {ref,watch} from 'vue'
    
    export default {
      name:'Demo',
      setup(){
        //数据
        let sum = ref(0)
        let msg = ref('你好啊')
    
        //情况一:监视ref所定义一个的响应式数据
        // watch(sum,(newValue,oldValue)=>{
        //   console.log('sum变了',newValue,oldValue)
        // })
    
        //情况二: 监视ref所定义的多个响应式数据
        //第一个参数:监听的数据。第二个参数:监听的函数。第三个参数:配置项
        watch([sum,msg],(newValue,oldValue)=>{
          //此时的newValue和oldValue就变成了数组
          console.log(newValue) //[0, '你好啊!']
          console.log(oldValue)//[0, '你好啊']
          console.log('sum变了',newValue,oldValue)
        },{immediate:true,deep:true})
    
        return {
          sum,
          msg
        }
      }
    }
    </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

    11.3 Vue3 watch监听reactive函数的数据


    监听格式如下:

    • 注意点1:如果watch直接监听的是reactive函数生成的代理对象,是无法正常获取oldValue的!!
    //就算用ref函数操作,因为是对象,对于对象ref还是走的reactive函数!
    let person = reactive({
      name:'张三',
      age:18
    })
    //监视reactive所定义的一个响应式数据
    watch(person,(newValue,oldVale)=>{
      //注意:这里newValue和oldVale一样,也就是无法获得正常的oldValue
      //这个问题目前无法解决!
      console.log(newValue)//{name: '张三~', age: 19}
      console.log(oldVale)//{name: '张三~', age: 19}
      console.log('person的age变化了')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    解决办法:如果无法业务上面真的需要获取到oldValue的话,那就只能把这个属性从对象中拿出来,放到ref函数中使用!

    //单独把age拿出来,用ref来声明就可以监听到!!
    let age = ref(18)
    
    //就算用ref函数操作,因为是对象,对于对象ref还是走的reactive函数!
    let person = reactive({
      name:'张三', 
    })
    //监视reactive所定义的一个响应式数据
    watch(age,(newValue,oldVale)=>{
      //注意:这里newValue和oldVale一样,也就是无法获得正常的oldValue
      //这个问题目前无法解决!
      console.log(newValue)
      console.log(oldVale)
      console.log('person的age变化了')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 注意点2:Vue3的watch强制开启了深度监视(deep配置无效!)。
      在这里插入图片描述

    • 注意点3:监听reactive函数对象的某个属性,步骤如下:

    let person = reactive({
      name:'张三',
      age:18,
      job:{
        j1:{
          salary: 20
        }
      }
    })
    //对象的某个属性,必须要用函数才能监听!!!
    watch(()=>person.age,(newValue,oldVale)=>{
      console.log(newValue)
      console.log(oldVale)
      console.log('person的age变化了')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 注意点4:监听对象的多个属性,形式如下:
    //监视reactive所定义的一个响应式数据中的 多个属性!
    let person = reactive({
      name:'张三',
      age:18,
      job:{
        j1:{
          salary: 20
        }
      }
    })
    //那就将其多个函数写成数组的形式
    watch([()=>person.age,()=>person.name],(newValue,oldVale)=>{
      console.log(newValue)
      console.log(oldVale)
      console.log('person变化了')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 注意点5:特殊情况!监听reactive代理对象的对象属性,这个时候就不再是强制深度监视,deep配置就奏效了!!!如果监视的是reactive代理对象,对于这个watch就是强制深度监视!!!
     let person = reactive({
       name:'张三',
       age:18,
       job:{
         j1:{
           salary: 20
         }
       }
     })
     //监听一个对象里面的对象属性,因为我们更改的是对象中的对象的对象数据!!
     //所以必须开启深度监视deep!!
     watch(()=>person.job,(newValue,oldVale)=>{
       console.log(newValue)
       console.log(oldVale)
       console.log('person的job变化了')
     },{deep:true})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    总结:
    在这里插入图片描述

    12. Vue3 之 watch的 .value问题


    注意点1:监听ref定义的基本数据类型,不能添加sum.value!!

    • 对于基本数据类型,如果添加上了.value那监听的就是sum.value的这个值!并不是sum这个变量!
    //数据
    let sum = ref(0)
    let msg = ref('你好啊')
    
    let person = ref({
      name:'张三',
      age:18,
      job:{
        j1:{
          salary: 20
        }
      }
    })
    
    //监听ref定义的基本数据类型,不能添加sum.value!!
    //如果添加上了.value那监听的就是sum.value的这个值!并不是sum这个变量!
    watch(sum,(newValue,oldValue)=>{
      console.log('sum的值变化了',newValue,oldValue)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    注意点2:ref代理对象的形式,通过.value来实现监听的效果。

    • 因为他是refImpl对象(ref函数)里面包含了proxy(reactive函数)对象,所以直接监视对象是监视不到的!
      在这里插入图片描述
    • 更加简单的方法,就是直接配置一个deep:false就可以了。深度监视
    let person = ref({
      name:'张三',
      age:18,
      job:{
        j1:{
          salary: 20
        }
      }
    })
    watch(person,(newValue,oldValue)=>{
      console.log('person的值变化了',newValue,oldValue)
    },{deep:true}) // 开启深度监视就能监视到了!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    13. Vue3 之 watchEffect函数


    watchEffect也是起到监听的效果,但宇watch不同!

    • watchEffect遵循用到了谁就监视谁!
    export default {
      name:'Demo',
      setup(){
        //数据
        let sum = ref(0)
        let msg = ref('你好啊')
    
        let person = reactive({
          name:'张三',
          age:18,
          job:{
            j1:{
              salary: 20
            }
          }
        })
    
        //watchEffect是用了谁,就监视谁!
        watchEffect(()=>{
          const x1 = sum.value
          const x2 = person.job.j1.salary
          console.log('watchEffect所指定的回调执行了!')
        })
    
        return {
          sum,
          msg,
          person
        }
      }
    
    • 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

    总结:

    • computed和watchEffect都是自己使用的数据发生变化就会调用执行,但是还是有区别的!
      在这里插入图片描述
  • 相关阅读:
    【重拾C语言】四、循环程序设计典例整理(最大公因数、阶乘求和、正整数翻译、打印字符方阵、斐波那契数列……)
    OSPF的原理与配置
    Java笔记 集合框架
    5.4 【MySQL】页目录
    Yolov5 计算访存量MAC与计算量FLOPS
    JAVANBA论坛系统计算机毕业设计Mybatis+系统+数据库+调试部署
    java基于springboot医疗器材管理系统
    记录一次用Navicat的保存表结构的sql文件的功能,运行后造成整个表数据丢失
    Java基础学习:深入解析Java中的位运算符
    1 论文笔记:Efficient Trajectory Similarity Computation with ContrastiveLearning
  • 原文地址:https://blog.csdn.net/IT_Holmes/article/details/126336582