携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情
前文中讲完了如何浅响应与深响应,在vue3中还新增了一个API,就是readonly,直译过来就是只读对象。
最常见的例子就是Props,不管是在vue2还是vue3,Props都是不应该被改变的,也就是只读。如果你这vue中修改了Props,你就会收到一条警告信息,这是vue3中的,vue2也有类似的。
那么,在vue3中是如何实现这个功能的呢。(vue2的源码我没研究过,有没有研究过的同学评论区稍微讲一下)
我们上一篇文章已经封装了出来了createReactive这个函数,基本结构如下,我们现在再次增加的参数,onlyRead,也是一个布尔类型,为了不影响上一篇封装出来的几个函数,我们让它默认为false
const createReactive = (obj,deepify = true,onlyRead=false)=>new Proxy(obj,{/*省略其他拦截*/})
其实所谓的只读就是不能修改,不能删除,因此我们就需要修改set和deleteProperty。这里set和deleteProperty的操作其实是一样的,我就省略一下了,要不然代码占比太高了。
const warnForReadOnly = (key)=>console.warn(`${key} is readonly`)
const createReactive = (obj,deepify = true,onlyRead=false)=>new Proxy(obj,{
set(target,key,newVal,receiver){
if(onlyRead){
warnForReadOnly(key)
return true
}
}
/*省略其他拦截*/
})
但是,这时候还有一个问题,当我们读取的时候,默认会追踪依赖,但是对于readonly来说,追踪依赖是多余的,它是不需要变化,也不需要响应的,因此我们需要在get的时候再处理下。在不是readonly的时候再追踪依赖即可
const createReactive = (obj,deepify = true, onlyRead=false)=>new Proxy(obj,{
get(target,key,receiver){
if(!onlyRead){
track(target,key)
}
/*省略其他逻辑*/
}
/*省略其他拦截*/
})
当然,和之前实现的reactive一样,这样的readonly也只是浅只读,我们也就可以按照之前的递归完善一下,弄一个深只读。
const createReactive = (obj,deepify = true, onlyRead=false)=>new Proxy(obj,{
get(target,key,receiver){
/*省略其他逻辑*/
if(deepify){
return res
}
if(res && typeof res === 'object'){
return onlyRead ? readonly(res) : reactive(res)
}
return res
}
/*省略其他拦截*/
})
const readonly = createReactive(obj,true,true)
const shallowReadonly = createReactive(obj,false,true)
这样就是实现了深只读与浅只读。下一章中,作者开始讲解如何代理数组,其实数组在vue中用的非常多,比如v-for中,在我看了这比代理对象更重要。