Vue3学习笔记(自用)

95 阅读4分钟

使用Proxy代替defineProperty实现响应式(数据劫持)

defineProperty的缺陷:

  1. 不能监听数组变化
  2. 只能劫持对象的属性而不是对象本身,给对象添加属性时无法检测到

Proxy弥补了这两种缺陷: “Proxy用于修改某些操作的默认行为,等同于对编程语言直接做出修改,属于‘元编程(meta progtamming)’, 即对编程语言进行编程”

更好地适用TS

Tree shaking

将全局API分块,如果未被使用,则不会被打包进生产代码。 典型例子就是在Vue3中computed, watch, onMounted都需要引入,如果未引入则不会被打包

Fragment

支持多个根节点,即template标签中可以有多个div标签了。

新的特性 Composition API

setup配置,ref与reactive...

//引入的不再是Vue构造函数,而是一个名为createApp的工厂函数
import { createApp } from 'vue'
import App from './App.vue'//创建应用实例对象:app。类似于之前Vue2中的vm,但app比vm属性更少,更轻量级
const app = createApp(App)
​
//挂载
app.mount('#app')
​

简写Vue3中的数据绑定

//源数据,(下面的p是代理数据
let person = {
    name: 'sxy',
    age: 23
}
​
//Vue2中的实现响应式(用于对比)
let p = {}
Object.defineProperty(p, 'name', {
    configurable: true,
    get(){//有人读取name时
        return person.name
    },
    set(){//有人修改name时调用
        person.name = value
    }
})
​
//模拟Vue3中实现响应式.使用ES6中的Proxy和Reflect
const p = new Proxy(person, {
    //有人读取p的某个属性时调用
    get(target, propName){
        console.log(`有人读取了p身上的${propName}属性`)
        return Reflect.get(target, propName)
    },
    //有人修改(增加)p的某个属性
    set(target, propName, value){
        console.log(`有人修改了p身上的${propName}属性,更新界面`)
    },
    //有人删除p的某个属性时调用
    deleteProperty(target, propName){
        console.log(`有人删除了p身上的${propName}属性,更新界面`)
        return Reflect.deleteProperty(target, propName)
    }
})

setup的两个注意点

  • setup的执行时机

    • beforeCreate之前执行一次,this是undefined
  • setup的参数

    • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性

    • context:上下文对象

      • attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于this.$attrs
      • slots:收到的插槽内容,相当于this.$slots
      • emit:分发自定义事件的函数,相当于this.$emit

计算属性的写法

import {reactive, computed} from 'vue'
export default {
    name: 'Demo',
    setup(){
        //数据
        let person = reactive({
            firstName: '张',
            lastName: '三'
        })
​
        //计算属性
        let fullName = computed(() => {
            return person.firstName + '-' + person.lastName
        })
​
        //返回一个对象
        return {
            person,
            fullName
        }
    } 
}

监视属性的写法

和Vue2并无太大区别。两个注意点

  • 对于reactive定义的对象数据。oldValue不能正确获取。
  • 对于reactive定义的对象数据。强制开启深度监视。
import {ref, reactive, watch} from 'vue'
export default {
    name: 'App',
    //Vue2中的写法
    watch:{
        //watch的简写形式
        // sum(newValue, oldValue){
        //   console.log('sum的值变化了', newValue, oldValue);
        // }
​
        //完整形式,可以设置配置项
        sum:{
            immediate: true,
            deep: true,
            handler(newValue, oldValue){
                console.log('sum的值改变了', newValue, oldValue);
            }
        }
    },
​
    setup(){
        let sum = ref(0)
        let msg = ref('Hello')
        let person = reactive({
            name: 'sxy',
            age: 23
        })
​
        //Vue3中的监视。参数1是监视的数据,参数2是监视的回调,参数3是监视的配置项
        //情况1:监视ref所定义的一个响应式数据
        watch(sum, (newValue, oldValue)=>{
            console.log('sum变了', newValue, oldValue);
        })
​
        //情况2:监视ref所定义的多个响应性数据
        watch([sum, msg], (newValue, oldValue)=>{
            console.log('sum或msg变了', newValue, oldValue);
        })
​
        //情况3:监视reactive所定义的一个响应式数据. 
        //此时无法正确获取oldValue。解决方法就是把数据拆开单独使用ref
        //并且强制开启深度监视
        watch(person, (newValue, oldValue)=>{
            console.log('person变了', newValue, oldValue);
        })
​
        //情况4:监视reactive所定义的一个响应式数据中的某一个属性
        watch(() => person.age, (newValue, oldValue) => {
            console.log('person的age变化了', newValue, oldValue);
        })
​
        //情况5:监视reactive所定义的一个响应式数据中的多个属性
        watch([()=>person.name, ()=>person.age], (newValue, oldValue)=>{
            console.log('person的name或age变化了', newValue, oldValue);
        })
​
        //特殊情况。
        //由于此时监视的是reactive定义的对象中的某个属性,并且这个属性依然是一个对象,所以deep配置有效
        watch(() => person.job, (newValue, oldValue) => {
            console.log('person的job变化了', newValue, oldValue);
        }, {deep: true})
​
        return {
            sum,
            msg,
            person
        }
    } 
}

Vue3生命周期

2个改变

  • beforeDestroy()destroyed()改名为beforeUnmount()unmounted()
  • 挂载之后才会开始生命周期。Vue2中会在created()之后检测是否挂载

除此之外,Vue3提供了Composition API形式的生命周期钩子,即在setup()中使用.

  • beforeCreated()created()没有对应的Composition API形式

  • 其它增加on

    • onBeforeMount
    • onMounted
    • onBeforeUpdate
    • onUpdated
    • onBeforeUnmount
    • onUnmounted
    //配置项形式写法
    beforeMount() {
        ...
    }
    ​
    //Composition API格式
    onBeforeMount(() => {
        ...
    })
    

自定义hook函数

一个用于复用的工具函数。把setup函数中使用的Composition API进行了封装

toRef

创建一个ref对象,其value值指向另一个对象中的某个属性

toRefs和toRef功能一致

\