Vue數(shù)據(jù)驅(qū)動模擬實現(xiàn)4
一、前言
在"模擬Vue之數(shù)據(jù)驅(qū)動3"中,我們實現(xiàn)了為每個對象擴展一個$set方法,用于新增屬性使用,這樣就可以監(jiān)聽新增的屬性了。
當然,數(shù)組也是對象,也可以通過$set方法實現(xiàn)新增屬性。
但是,對于數(shù)組而言,通常我們是通過push之類的方法吧。
PS:Vue中明確指出push、pop、shift、unshift、splice、sort、reverse方法為變異方法,可以通過它們監(jiān)聽屬性變化,觸發(fā)視圖更新(詳情見here)
下面,我們就一起來實現(xiàn)這些Array的變異方法吧。
注:我們將Array變異方法實現(xiàn),也寫在extendObj.js中的,因為數(shù)組也是對象嘛。
二、Array變異方法實現(xiàn)
要實現(xiàn)這些變異方法,毫無疑問,我們會重寫它們,那在Array.prototype里面重寫嗎?
當然不是,這樣不就影響了所有數(shù)組對象的原型鏈了么!
為了避免這種情況,且,我們只是想在監(jiān)聽數(shù)據(jù)對象上繼承這些變異數(shù)組方法,那么細心的你會發(fā)現(xiàn),其實與我們在"模擬Vue之數(shù)據(jù)驅(qū)動3"中實現(xiàn)$set方法類似了。
首先,我們創(chuàng)建arrKeys對象用于保存需要變異的數(shù)組方法以及恒定對象extendArr,如下:
let arrKeys = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']; const extendArr = [];
接著,就是在extendArr對象上,一一監(jiān)聽arrKeys中的方法了,與$set方法類似,整體結(jié)構(gòu)如下:
!function(){ arrKeys.forEach(function(key){ proxyObject(extendArr, key, function(){ //TODO }); }); }();
注:proxyObject方法其實核心就是Object.defineProperty,詳見"模擬Vue之數(shù)據(jù)驅(qū)動3".
接下來,就是實現(xiàn)核心部分代碼了,重寫這些方法的目的,是為了監(jiān)聽數(shù)據(jù)變化,所以要在方法原有功能不變的情況下,重寫它們,Array.xxx.apply即可實現(xiàn)原有功能。
且,push、unshift、splice這三個方法可以在原數(shù)組中,新增屬性,故而,我們需要監(jiān)聽新增屬性以及它們的屬性值,這里就和$set方法完全一樣了,通過$Observer,即可利用observe以及convert方法實現(xiàn)了。
實現(xiàn)代碼如下:
!function(){ arrKeys.forEach(function(key){ proxyObject(extendArr, key, function(){ console.log('Fun ' + key + ' is observed'); let result; let arrProto = Array.prototype; let ob = this.$Observer; let arr = arrProto.slice.call(arguments); let inserted; let index; switch(key){ case 'push': { inserted = arr; index = this.length; break; } case 'unshift': { inserted = arr; index = 0; break; } case 'splice': { inserted = arr.slice(2); index = arr[0]; break; } } result = arrProto[key].apply(this, arguments); if(inserted){ inserted.forEach(val => { ob.observe(val); ob.convert(index++, val); }); } return result; }); }); }();
最后,就是在需要監(jiān)聽的對象上繼承這些變異方法咯,如下:
//observer.js function Observer(data){ if(!(this instanceof Observer)){ return new Observer(data); } data.__proto__ = extendObj; //繼承變異方法push、pop等等 if(Array.isArray(data)){ data.__proto__.__proto__ = extendArr; } this.data = data; this.walk(data); }
好了,一切完畢,接下來就測試下唄:
<script src="./extendObj.js"></script> <script src="./observer.js"></script> <script> 'use strict'; let data = { msg: [5, 2, 0], user: { name: 'Monkey', age: 24 }, lover: { name: 'Dorie', age: 23 } }; Observer(data); </script>
效果如下:
Perfect,此時,你可能會想,數(shù)組方法中僅有push、unshift、splice會為數(shù)組新增屬性,那么我們又何必將其他方法,例如sort、reverse重寫呢,也沒發(fā)現(xiàn)有什么貓膩呢?
不錯,在此時,并沒有什么卵用,但是,你要知道sort、reverse等這些方法,可是會引起數(shù)組變化的,那么就會影響視圖展現(xiàn),這些變化,又怎么通知數(shù)組呢?就是下篇隨筆會具體說明的。
該篇隨筆代碼,詳情見github.
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
UNIapp實現(xiàn)局域網(wǎng)內(nèi)在線升級的操作方法
這篇文章主要介紹了UNIapp實現(xiàn)局域網(wǎng)內(nèi)在線升級的操作方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-03-03解決Vue.js 2.0 有時雙向綁定img src屬性失敗的問題
下面小編就為大家分享一篇解決Vue.js 2.0 有時雙向綁定img src屬性失敗的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03如何解決this.$refs.form.validate()不執(zhí)行的問題
這篇文章主要介紹了如何解決this.$refs.form.validate()不執(zhí)行的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09vue和webpack項目構(gòu)建過程常用的npm命令詳解
本文通過實例代碼給大家介紹了vue和webpack項目構(gòu)建過程常用的npm命令,需要的朋友可以參考下2018-06-06VUE3使用Element-Plus時如何修改ElMessage中的文字大小
在使用Element-plus的Elmessage時使用默認的size無法滿足我們的需求時,我們可以自定義字體的大小,但是直接重寫樣式后,并沒有起作用,甚至使用::v-deep深度選擇器也沒有效果,本文介紹VUE3使用Element-Plus時如何修改ElMessage中的文字大小,感興趣的朋友一起看看吧2023-09-09vue.js實現(xiàn)仿原生ios時間選擇組件實例代碼
本篇文章主要介紹了vue.js實現(xiàn)仿原生ios時間選擇組件實例代碼,具有一定的參考價值,有興趣的可以了解一下。2016-12-12在vue中使用防抖和節(jié)流,防止重復點擊或重復上拉加載實例
今天小編就為大家分享一篇在vue中使用防抖和節(jié)流,防止重復點擊或重復上拉加載實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11