2.ref函数:
作用:定义一个响应式的数据
语法:const xxx=ref(initValue)
创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
js种操作数据 :xxx.value
模板中读取数据,不需要value,直接 <div>{xxx}</div>
备注:
接受的数据可以是:基本类型,也可以是对象类型
基本类型的数据:响应式依然是靠 get和set完成的
对象类型的数据:内部求助了Vue3.0中的一个新函数,——reactive函数
3.reactive函数
作用:定义一个对象类型的响应式数据(基本类型别用它,用ref函数)
语法:const 代理对象=reactive(被代理对象)接受一个对象(或者是数组),返回一个代理对象( proxy对象)
reactive定义的响应式数据是”深层次“的
内部基于 ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作
4.Vue3.0中的响应式原理
vue2.0x的响应式
实现原理:
对象类型:通过Object.defineProperty()对对象的已有属性值的读取,修改进行拦截(数据劫持)
数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)
Object.defineProperty(data,'count',{get() {},set() {},})
存在问题:
新增属性,删除属性,界面不会更新
直接通过下标修改数组,界面不会自动更新
Vue3.0x的响应式
实现原理
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写,属性的添加,属性的删除等。
通过Reflect(反射):被代理对象的属性进行操作
MDN文档当中的Proxy 和 Reflect:
Proxy:
Reflect:
new Proxy(data,{
get(target,prop){
return Reflect.get(target,prop)
},
//拦截设置属性值或者是添加新属性
set(target,prop,value){
return Reflect.set(target,prop,value)
}
})
target对象里面是没有propName属性的,所以用 . 的方式是找不到变量名字是propName的属性的
对象属性的读取必须必须使用 []
propName是一个字符串,你见过obj.'name' 这么操作的么
5.reactive对比ref
从定义数据角度对比
ref用来定义:基本数据类型
rective用来定义:对象(或者是数组)类型数据
备注:ref也可以来定义对象(或者数组)类型数据,它内部会自动通过reactive转换为代理对象
从原理角度对比:
ref通过Object.defineProperty() 的 get 和 set 来实现响应式(数据劫持)
reactive通过使用Prxoy来实现响应式(数据劫持),并且通过Reflect操作源对象内部的数据
从使用角度对比
ref定义的数据:操作数据需要 .value ,读取数据的时候模板中直接读取,不需要 .value
reactive定义的数据:操作数据和读取数据都不需要 .value
6.setup的两个注意点儿
setup执行的实际
在beforeCreate之前执行一次,this是undefined
setup的参数
props:值是对象,包含:组件外部传递过来,并且组件内部声明接收了的属性
context:上下文对象
attrs:值是对象,包含:组件外部传递过来,但是没有在props配置中声明的属性,相当于 this.$attrs
slots:收到的插槽内容,相当于 this.$slots。
emit:分发自定义事件的函数,相当于 this.$emit
7.计算属性和监视
1.computed函数
和vue2.0x中computed配置功能一致
写法
import {computed} from 'vue'
setup(){
...
//计算属性——简写
let fullName=computed(()=>{
return person.firstName+'-'person.lastName
})
//计算属性——完整
let fullName=computed({
get(){
return person.firstName+'-'+person.lastName
},
set(value){
const nameArr=value.split('-')
person.firstName=nameArr[0]
person.lastName=nameArr[1]
}
})
}
2.watch函数
和vue2.0x中watch配置功能一致
两个小坑:
监视reactive定义的响应式数据的时候:oldValue无法正确获取,强制开启了深度监视(deep配置失效)
监视reactive定义的响应式数据中某个属性的时候:deep配置有戏
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
//情况二:监视ref所定义的多个响应式数据,一个数组
watch([sum ,msg],(newValue,oldValue)=>{
console.log('sum变了',newValue,oldValue);
},{immediate:true,deep:true})
/*情况三:监视reactive所定义的一个响应式数据的全部属性
1.注意:此处无法正确的获取oldValue,
2.强制开启了深度监视(也就是deep配置无效)
**/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue);
},{deep:false})//此时的deep配置无效
//情况四:监视reactive所定义的一个响应式数据中的某个属性.需要写成一个函数,让人家帮你调用
watch(()=>person.age,(newValue,oldValue)=>{
console.log('person的age变化了',newValue,oldValue);
},{deep:false})
//情况五:监视reactive所定义的一个响应式数据中的某些属性
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
console.log('person的name或者是age变化了',newValue,oldValue);
})
//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person里面的job变化了',newValue,oldValue) ;
},{deep:true})//此处由于监视的是reactive中定义的对象的某个属性,所以,deep配置有效
也就是说,如果你监视的如果是个对象,手动自动开始深度监视都无效,如果监视的是对象里面的基本数据类型,默认开启的深度监视有效,第三种要监视对象内的对象要手动开启深度监视
3.watch函数
watch的套路是:既要知名监视的属性,也要指明监视的回调
watchEffect的套路是:不用知名监视哪个属性,监视的会调用中用到哪个属性,那就监视哪个属性
watchEffect有点儿像computed
但是computed注重的计算出来的值 (回调函数的返回值),所以必须要些返回值
但是watchEfferc更注重的是过程(回调函数的函数体),所以不用写返回值
//watchEffect所指定的回调中用到的数据只要发生变化,就直接重新执行回调
watchEffect(()=>{
const x1=sum.value
const x2=person.age
console.log('watchEffect配置的回调执行了')
})
8.生命周期
vue3.0中可以继续使用vue2.0中的生命周期钩子,但是有两个已经被改名
beforeDestory改名为beforeUnmount
destoryed改名为unmounted
vue3.0也提供了Composition API形式的生命周期钩子,和vue2.0x中钩子的对应关系如下
beforeCreate => setup()
created => setup()
beforeMount =>onBeforeMount
mounted =>onMounted
beforeUpdate =>onBeforeUpdate
updated =>onUpdated
beforeUnmount =>onBeforeUnmount
unmounted =>onUnmounted
9.自定义hook函数
什么是hook?——本质是要给函数,把setup函数中使用的CompoistionApi进行了封装
类似于vue2.0x中的mixin
自定义Hook的优势:复用代码,让setup中的逻辑更清楚易懂
10.toRef
作用:创建一个ref 对象,其value值指向另一个对象中的某个属性值
语法:const name=toRef(perosn,'name')
应用:要将响应式对象中的某个属性单独提供给外部使用的时候
扩展:toRefs 和 toRef功能一致,但是可以批量创建多个ref对象,语法: toRefs(person)