Vue3 比 Vue2 什么优势?
- 性能更好
- 体积更小
- 更好的 TS 支持
- 更好的代码组织
- 更好的逻辑抽离
Composition API 的优点
- 更好的代码组织
- 更好的逻辑复用
- 更好的类型推导
如何理解 ref、toRef 和 toRefs
ref
- 生成值类型的响应式数据
- 可用于模板和 reactive
- 通过 .value 修改值
- ref值变量尽量使用 Ref 后缀,如:ageRef
通过 ref 可获取 DOM 节点
toRef
- 创建一个 ref 对象,其value值指向另一个对象(reactive 封装)中的某个属性
- 两者保持引用关系
语法:
const name = toRef(person,'name')
应用: 要将响应式对象中的某个属性单独提供给外部使用时。
扩展:
toRefs
与toRef
功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)
ref、toRef 和 toRefs 的最佳使用方式
- 用 reactive 实现对象的响应式,用 ref 实现值类型的响应式
- setup 中返回 toRefs(state) ,或者 toRef(state,'xxx')
- ref 的变量命名都用 xxxRef
- 合成函数返回响应式对象时,使用 toRefs
为何需要 ref
- 不使用 ref ,值类型会丢失响应式
- 如在 setup、computed、合成函数,都有可能返回值类型
- Vue 不定义 ref,用户将自造 ref,反而混乱
为何需要 .value
- ref 是一个对象(不丢失响应式),value 用来存储值
- 通过 .value 属性的 get 和 set 实现响应式
- 用于模板、reactive 时,不需要 .value,其他情况都需要
为何使用toRef 和 toRefs
- 初衷:在不丢失响应式的情况下,解构 reactive 的响应式对象
vue3升级了哪些重要的功能(与 vue2 的区别)
vue3 启用 createApp,vue2使用的是 new Vue
vue3 新增 emits 属性,使用需要先声明
vue2使用 $emit(自定义事件)
多事件处理
注意:不能采用简写形式,必须写成函数
vue3 template标签中无需根节点
移除 .sync(用于 prop 的双向绑定)
异步组件
Teleport(任意门)
Composition API
- reactive
- ref、toRef、torefs
- readonly
- watch 和 watchEffect
- setup
- 生命周期钩子
vue3的响应式
vue2 和 vue3 响应式对比,见vue2 总结
Proxy 的基本使用
语法: new Proxy( target, handler )
target:
要使用Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。handler
:
p
的行为。- get( target, key, receiver)
- set( target, key, val, receiver)
- deleteProperty( target, key)
const reactive = function(data){
//排除值类型数据
if(typeof data !== 'object' || data == null){
return data
}
const proxyObj = {
get(target, key, recevie){ //target:即传入的对象 data key:读取的键名 recevie:整个Proxy对象
const ownKeys = Reflect.ownKeys(target)
//排除使用数组方法时,多输出的方法名称
if(ownKeys.includes(key)){
console.log('get',key)
}
const result = Reflect.get(target, key, recevie)
//深层监听
//性能提升:获取到哪层,哪层触发响应式
return reactive(result)
},
set(target, key, val, recevie){ //target:即传入的对象 data key:修改的键名 val:修改的值(新,即 newval) recevie:整个Proxy对象
//oldval 和 newval 相同时,直接输出
if(target[key] === val){
return true
}
//判断是否为新增的属性
const ownKeys = Reflect.ownKeys(target)
if(ownKeys.includes(key)){
console.log('已存在的属性')
}else{
console.log('新的属性')
}
const result = Reflect.set(target, key, val, recevie)
return result
},
deleteProperty(target, key){ //target:即传入的对象 data key:想要删除的键名
const result = Reflect.deleteProperty(target, key)
return result
}
}
const result = new Proxy(data,proxyObj)
return result
}
const data = {
name:'zhangsan',
age:18,
hobby:{
PE: 'swim',
},
}
// const data = ['a','b','c','d']
const rea = reactive(data)
// rea.name = 'lisi',
// rea.push('v')
// console.log(rea.name)
console.log(rea.hobby.PE)
watch 和 watchEffect 的区别
- 两者都可以监听 data 属性的变化
- watch 需要明确监听哪个属性
- watchEffect 会根据其中的属性,自动监听其变化,初始化时一定会执行一次
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变化了',newValue,oldValue)
})
/* 情况三:监视reactive定义的响应式数据
若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效
//情况四:监视reactive定义的响应式数据中的某个属性
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
//情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
- watch的套路是:既要指明监视的属性,也要指明监视的回调。
- watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
- watchEffect有点像computed:
- 但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值。
- 而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
//初始话时一定会执行一次
watchEffect(()=>{
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
sutup 中如何获取组件实例(this)
- 在 setup 和 composition API 中没有 this
- 可通过 getCurrentInstance 获取当前实例(this)
- 使用 Options API 可照常使用 this
Vue3 为何比 Vue2 快
- Proxy 响应式:vue2 采用的响应式是一次性递归所有,计算量大,vue3 采用的响应式用到哪里递归到哪里,单次计算量小,运行速度快;
- PatchFalg:编译模板时,给动态模板做标记,且为其区分不通的类型,在执行 diff 算法时,可以区分静态节点,以及不同类型的动态节点,diff 算法会跳过静态文本节点的比较;
- hoistStatic:将静态节点的定义提升到父作用域,缓存起来,多个相邻的静态系节点会被合并起来,典型的用空间换时间的做法
- cacheHandler:缓存事件
- SSR(服务端渲染)优化:静态节点直接输出,绕过 vdom,动态节点依旧渲染;