vue響應(yīng)式Object代理對象的修改和刪除屬性
正文
上一篇文章我們學(xué)習(xí)了如何代理對象的讀取,下面我們學(xué)習(xí)如何代理對象的修改和刪除屬性。
set
set就是修改代理的屬性,按照我們之前寫的reactive,它大概是這樣的
const ITERATE_KEY=symbol() const p = new Proxy(obj,{ set(target,key,newVal,receiver){ const res = Reflect.set(target,key,newVal,receiver) trigger(target,key) return res } }
細心的朋友應(yīng)該發(fā)現(xiàn)了,我專門把ITERATE_KEY
也加進來了,但是在set中并沒有使用,難道是多余的?
這里其實有一個小坑,就是如果曾經(jīng)對對象使用過for ... in
,這里會出現(xiàn)2種情況:
- 如果我們新增了一個屬性,那么我們是不是應(yīng)該重新運行一次
for ... in
的副作用函數(shù)。 - 如果我們只是修改某個屬性而不是新增,那么我們就不應(yīng)該重新運行
for ... in
的副作用函數(shù). 所以我們需要判斷一下它是新增還是修改
//定義常量,在ts中可以使用枚舉 const TriggerType = { SET:'SET', ADD:'ADD' } const p = new Proxy(obj,{ set(target,key,newVal,receiver){ //判斷新增還是修改 const type = Object.prototype.hasOwnProperty.call(target,key) ? TriggerType.SET : TriggerType.ADD const res = Reflect.set(target,key,newVal,receiver) trigger(target,key,type) return res } }
同時,對應(yīng)trigger函數(shù)中,我們也需要根據(jù)type讀取ITERATE_KEY
對應(yīng)的副作用函數(shù).
const trigger = (target,key,type)=>{ const depsMap = targetMap.get(target) if(!depsMap){ return } const effects = depsMap.get(key) // 再次去重 const needToRun = new Set() if(effects){ effects.forEach(e=> e!==activeEffect ? needToRun.add(e) : '' ) } if(type === TriggerType.ADD){ const otherEffects = depsMap.get(ITERATE_KEY) if(otherEffects){ otherEffects.forEach(e=> e!==activeEffect ? needToRun.add(e) : '' ) } } if(needToRun.length){ needToRun.forEach(fn=> fn?.options?.scheduler ? fn.options.scheduler(fn) : fun()) } }
這樣,我們只在新增的時候才會調(diào)用for ... in
的副作用函數(shù)。
delete
刪除的時候,之前貌似沒寫過。這里需要注意2個點。
- 保證屬性刪除之后才運行副作用,這里從邏輯上講我們最好先驗證這個屬性是否存在,避免報錯。
- 刪除時也要運行
for ... in
的副作用函數(shù)
因此我們這樣定義,給TriggerType
新增一個類型DEL
const TriggerType = { SET:'SET', ADD:'ADD', DEL:'DELETE' }
然后,我們開始攔截刪除屬性的操作,查一下之前的Proxy
內(nèi)部方法的表,我們可以得知,刪除屬性對應(yīng)著deleteProperty
方法。
const p = new Proxy(obj,{ deleteProperty(target,key){ //判斷屬性存在,你總不能刪除一個不存在的屬性吧 const hadKey = Object.prototype.hasOwnProperty.call(target,key) const res = Reflect.deleteProperty(target,key) if(res && hadKey){ trigger(target,key,TriggerType.DEL) } return res } }
對應(yīng)trigger函數(shù)中,我們小修改一下,其他邏輯不變
// 刪除這句 - if(type === TriggerType.ADD){ // 改為 + if([TriggerType.ADD,TriggerType.DEL].includes(type)){
這樣就可以實現(xiàn)響應(yīng)式對象的刪除屬性。
其實原文中并沒有使用Array.includes
,但我覺得其實我們應(yīng)該使用最新的語法,現(xiàn)在瀏覽器環(huán)境對這些新語法支持度已經(jīng)很好了(如果你要兼容IE當我沒說)。
這一篇就完結(jié)了,總結(jié)一下就是如何對對象的讀取屬性、修改屬性、刪除屬性進行代理,大概了解vue3中對于對象的處理。
但是這里還沒有結(jié)束,后續(xù)會講一些邊際條件,以及如何合理的響應(yīng)數(shù)據(jù)變化和操作,合理也就是優(yōu)化,盡可能的減少多余的響應(yīng)。
更多關(guān)于vue響應(yīng)式Object修改刪除的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解使用vue-cli腳手架初始化Vue項目下的項目結(jié)構(gòu)
這篇文章主要介紹了詳解使用vue-cli腳手架初始化Vue項目下的項目結(jié)構(gòu),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03elementUI vue this.$confirm 和el-dialog 彈出框 移動 示例demo
這篇文章主要介紹了elementUI vue this.$confirm 和el-dialog 彈出框 移動 示例demo,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07vue計算屬性無法監(jiān)聽到數(shù)組內(nèi)部變化的解決方案
今天小編就為大家分享一篇vue計算屬性無法監(jiān)聽到數(shù)組內(nèi)部變化的解決方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11vue+echarts實現(xiàn)動態(tài)繪制圖表及異步加載數(shù)據(jù)的方法
vue寫的后臺管理,需要將表格數(shù)據(jù)繪制成圖表(折線圖,柱狀圖),圖表數(shù)據(jù)都是通過接口請求回來的。這篇文章主要介紹了vue+echarts 動態(tài)繪制圖表及異步加載數(shù)據(jù)的相關(guān)知識,需要的朋友可以參考下2018-10-10vue 中 elment-ui table合并上下兩行相同數(shù)據(jù)單元格
這篇文章主要介紹了vue 中 elment-ui table合并上下兩行相同數(shù)據(jù)單元格,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12