一、setup函数
setup:一般返回一个对象,对象的key可以直接使用(也可以返回一个渲染函数)
注意:
- 正常情况下setup不能是一个async函数,因为返回值不再是return的对象, 而是promise,模板看不到return对象中的属性,则组件不会被渲染出来。
- 但是如果配合新增的组件Suspense和异步组件的引用方式,也可以返回一个Promise实例,具体查看 vue3新的组件
二、ref函数
创建一个响应值:ref(“张三”),ref({ name:“张三” }),返回一个RefImpl对象(引用实现的实例化对象,简称引用对象,也叫ref对象)
操作基础类型的响应值:ref(“张三”).value,ref(“张三”).value = “李四”
操作引用类型的响应值:ref({ name:“张三” }).value.name,ref({ name:“张三” }).value.name = “李四”
重点:ref函数返回的是ref对象,当创建的是基础类型的响应式是使用的是object.defineproperty的get与set方法进行数据劫持;当创建的是引用类型时使用的是ES6里面的 Proxy对象 进行代理实现的(实际上是求助了reactive函数)
三、reactive函数
作用:定义一个对象类型的响应式数据(基础类型不能用它)
创建一个响应值:const 代理对象 = reactive(源对象),返回一个代理对象(Proxy的实例化对象,简称Proxy对象)
操作响应值:reactive({ name:“张三” }).name,reactive({ name:“张三” }).name = “李四”
四、回忆vue2 的响应式
1. 实现原理
- 对象类型:进行递归遍历对象的属性进行object.defineproperty的数据劫持
- 数组类型:通过重写更新数组的一系列方法来进行实现拦截。(对数组的变更方法进行包裹)
2. 存在问题
-
新增,删除属性时,界面不会更新
-
直接通过下标修改数组,界面不会更新
-
得采用 s e t , set, set,delete,splice等方式进行修改
四、了解vue3 的响应式
实现原理:
- 通过Proxy(代理):拦截对象中任意属性的变化
- 通过Reflect(反射):对源对象的属性进行操作(好处是Reflect不会直接抛错)
const data = {
name:"haonan"
}
const proxy = new Proxy(data, {
//拦截读取属性
get(target,prop){
return Reflect.get(target,prop)
},
//拦截修改和新增属性
set(target,prop,value){
return Reflect.set(target,prop,value)
},
//拦截删除属性
defineProperty(target,prop){
return Reflect.defineProperty(target,prop)
},
})
proxy.name = "henry"
五、setup的两个注意点
setup执行的时机:在beforeCreate之前执行一次,this是undefined
setup的参数:
- props:值为Proxy对象,包含 组件外部传递过来,且组件内部声明接收了的属性
- context:上下文对象
attrs:值为对象,包含 组件外部传递过来,但没有在props内部声明的属性,相当于vue2中的
this.$attrs
。
slots:收到的插槽内容,相当于this.$slots
。(vue3中得写成v-slot:
,不要写成solt=""
)
emit:分发自定义事件的函数,相当于this.$emit
。
六、计算属性与监视
1.computed函数
import { computed,reactive } from "vue";
setup() {
const user = reactive({
firstName: "张",
lastName: "三",
});
//简写
user.fullName = computed(() => {
return user.firstName + "-" + user.lastName;
});
//完整写法
user.fullName = computed({
set(value){
const arr = value.split('-')
user.firstName = arr[0]
user.lastName = arr[1]
},
get(){
return user.firstName + "-" + user.lastName;
}
});
return {
user,
};
},
2.watch函数
需要注意:
- 监听reactive定义的响应式数据时:oldValue无法正确获取、且是强制的深度监听(deep配置失效)
- 监听reactive定义的响应式数据中的某个属性时:不会深度监听,deep配置依旧有效
- 当监听的是reactive定义的响应式数据中的某个属性时,需要使用
()=>
包裹监听的数据属性
const user = reactive({
name:"henry",
job:{
c:'1',
a:{
b:222
}
}
})
watch(user,(newval,oldval)=>{
console.log('user',newval,oldval)
},{
immediate:true,//有效
deep:false //无效,当监听的对象是Proxy对象时,强制开启深度监听,且无法正确获取oldVal
})
watch([()=>user.name,()=>user.job.a.b],(newval,oldval)=>{//多个监听时,可以用数组的形式
console.log('名称和薪资有更新',newval,oldval)
})
watch(()=>user.name,(newval,oldval)=>{//当你监听的是对象的属性,并且是一个基础类型时,一定得用'()=>'的方式监听
console.log('名称有更新',newval,oldval)
})
watch(()=>user.job,(newval,oldval)=>{//当你监听的是对象的属性,并且该属性的值是一个对象时,可用可不用'()=>'的方式监听,此时不会开启深度监听,需要配置deep才能开启深度监听
console.log('job有更新',newval,oldval)
},{
deep:true
})
当使用ref创建对象类型的数据时,由于ref内部是求助了reactive函数,所以需要监听.value
或者开启deep,此时依旧无法正确获取oldVal
//方式一:
watch(user,(newval,oldval)=>{
console.log('user',newval,oldval)
},{
deep:true
})
//方式二:
watch(user.value,(newval,oldval)=>{
console.log('user',newval,oldval)
})
3.watchEffect函数
作用:监听函数内用到所有属性
watchEffect(()=>{
user.income = user.income1 + user.income2
user.expend = user.expend1 + user.expend2
user.total = user.income - user.expend
console.log('watchEffect user++++',user)
})
watchEffect 有点像 computed:
- computed注重结果,需要写返回值
- watchEffect注重过程,不用写返回值
七、生命周期
1.改名
beforeDestroy(不起作用了) => beforeUnmount
destroyed(不起作用了) => unmounted
2.composition API形式的生命周期
beforeCreate => setup
created => setup
beforeMount => onBeforeMount
mounted => onMounted
beforeUpdate => onBeforeUpdate
updated => onUpdated
beforeUnmount => onBeforeUnmount
unmounted => onUnmounted
3.composition API 和 生命周期配置 的优先级
尽管开发时,不太可能即用composition API和生命周期配置,但需了解 composition API 比 生命周期配置先触发
4.el
vue2时,即使你没有配置el,beforeCreate和created也会触发;
而vue3中,如果你没有配置el,则不会触发beforeCreate和created
八、自定义hook函数
本质是一个函数,把setup函数中使用的composition API进行了封装
类似于vue2中的mixin
优势:复用代码,让setup中的逻辑更清楚易懂
PS:尽量使用use***
命名,例如usePoint
九、toRef
创建一个ref对象,其value值指向另一个响应式对象中的某个属性
const name = toRef(user,'name')
const c = toRef(user.job.a,'c')
可以用来将响应式对象中的某个属性单独提供给外部使用
如果要创建扩展一个响应式对象的所有属性时,可以用toRefs
setup() {
const user = reactive({
name:"henry",
age:25
})
return {
...toRefs(user)
};
}