1.组合式API和声明式API的区别,组合式API的优点
2.Vue3的响应式原理
通过Proxy(代理):拦截对象中任意属性的变化:包括:属性值的读写、属性的添加、属性的删除等。
通过reflect(反射):对被代理对象的属性进行操作
let person={ name:'张三', age:18 } let p=new Proxy(person,{ get(target,propname){ console.log(`请求获取p(${target})中的${propname}`); // return target[propname] return Reflect.get(target,propname) }, set(target,propname,value){ console.log(`修改p(${target})中的${propname}`); // target[propname]=value Reflect.set(target,propname,value) }, delete(target,propname){ console.log(`删除p(${target})中的${propname}`); // return delete target[propname] return Reflect.defineProperty(target,propname) } })
3.ref和reactive
对比:
从定义角度:
ref用来定义:基本类型数据
reactive用来定义:对象和数组类型数据
备注:ref也可以用啦定义对象和数组类型的数据,它内部会自动通过reactive转为代理对象
从原理角度对比:
ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)
reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect来操作源对象的内部数据
从使用角度:
ref定义的数据:操作数据需要.value,读取数据时模版中直接读取不需要value
reactive:操作数据与读取数据:均不需要.value
ref用来处理基本数据类型也可以处理对象类型,在处理数据时,例如修改数据需要在变量后面加上value,
使用ref
<script setup> import { ref, reactive } from 'vue' let name=ref('jack') let age=ref(18) let item=ref({ job:'前端开发工程师', salary:'50k' }) function increment(){ name.value='jonh', age.value=118, item.value.job='UI' } </script> <template> <div> <h1>一个人的信息</h1> <h2>姓名:{{name}}</h2> <h2>年龄:{{age}}</h2> <h2>职业:{{item.job}}</h2> <h2>薪水:{{item.salary}}</h2> <button @click="increment">修改个人信息</button> </div> </template>
处理对象类型和数组类型的数据时,使用reactive,不建议使用reactive处理基本数据类型
使用reactive之后,就不需要通过加上value来改变原先的值
<script setup> import { ref, reactive } from 'vue' let name=ref('jack') let age=ref(18) let item=reactive({ job:'前端开发工程师', salary:'50k' }) function increment(){ name.value='jonh', age.value=118, item.job='UI' } </script>
3.setup的两个注意点
setup的执行时机
在beforeCreate之前执行一次,this是undefined,所在在setup中是不能使用this的因为
什么都获取不到
setup参数
props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性
context:上下文对象
attrs:值为对象,包含:组件外部传递过来的,但是没有在props配置中声明的属 性,相对应this.$attrs.
slots:收到的插槽内容,相对应this.$solts.
emit:分发自定义事件的函数,相当于this.$emit.
4.computed函数、
setup(){ let firstName=ref('') let lastName=ref('') // let fullName=computed(()=>{ // return firstName.value+'-'+lastName.value // }) let fullName=computed({ get(){ return firstName.value+'-'+lastName.value }, set(value){ let nameArr=value.split('-') firstName.value=nameArr[0] lastName.value=nameArr[1] } }) return { firstName, lastName, fullName } }
5.watch
情况一:监听ref所定义的一个响应式数据
//情况一:监听ref所定义的一个响应式数据 watch(sum,(oldValue,newValue)=>{ console.log('监听到了改变',oldValue,newValue); })
情况二:监听ref所定义的多个响应式数据
watch([sum,msg],(newValue,oldValue)=>{ console.log('sum or msg 变化了',newValue,oldValue); })
情况三:监听reactive所定义的一个响应式数据
1.注意:此处无法正确获取oldValue
2.注意:强制开启了深度监视(deep配置无效)
watch(person.value,(newValue,oldValue)=>{ console.log('person变化了',newValue,oldValue); })
情况四:监听reactive所定义的一个响应式数据中的某个属性
watch(()=>person.name,(newValue,oldValue)=>{ console.log('person的name变化了',newValue,oldValue); })
情况五:监视reactive所定义的一个响应式数据中的某些属性
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{ console.log('person的name和age变化了',newValue,oldValue); })
特殊情况:使用deep监听深层数据的变化 (此处因为监听的是reactive中的对象中的某个属性依然是个对象,所以deep配置有效)
watchEffect
watch的套路:既要指明监听的属性,也要指明监视的回掉
watchEffect的套路是:不用指明监视的哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
watchEffect有点像computed
但computed注重计算的出来的值(回调函数的返回值),所以必须要写返回值
而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值
watchPostEffect
watchProxyEffect
6.render函数
render函数使得我们使用js构建dom
当使用精简版vue库的时候,没有模版解析器,那怎么构建dom呢,这个时候需要使用render函数,将模版template解析成js文件从而构建虚拟dom,就省去了vue转译的过程,
其实都是将模版解析为虚拟dom树
当使用完整版的vue库的时候,含有模版解析器,模版解析占用vue库大概三分之一的空间,在webpack打包的时候,模版解析器一直在,其实,使用精简版vue旨在减少打包的内存