Vue數(shù)據(jù)驅(qū)動(dòng)模擬實(shí)現(xiàn)4
一、前言
在"模擬Vue之?dāng)?shù)據(jù)驅(qū)動(dòng)3"中,我們實(shí)現(xiàn)了為每個(gè)對(duì)象擴(kuò)展一個(gè)$set方法,用于新增屬性使用,這樣就可以監(jiān)聽(tīng)新增的屬性了。
當(dāng)然,數(shù)組也是對(duì)象,也可以通過(guò)$set方法實(shí)現(xiàn)新增屬性。
但是,對(duì)于數(shù)組而言,通常我們是通過(guò)push之類(lèi)的方法吧。
PS:Vue中明確指出push、pop、shift、unshift、splice、sort、reverse方法為變異方法,可以通過(guò)它們監(jiān)聽(tīng)屬性變化,觸發(fā)視圖更新(詳情見(jiàn)here)
下面,我們就一起來(lái)實(shí)現(xiàn)這些Array的變異方法吧。
注:我們將Array變異方法實(shí)現(xiàn),也寫(xiě)在extendObj.js中的,因?yàn)閿?shù)組也是對(duì)象嘛。
二、Array變異方法實(shí)現(xiàn)
要實(shí)現(xiàn)這些變異方法,毫無(wú)疑問(wèn),我們會(huì)重寫(xiě)它們,那在Array.prototype里面重寫(xiě)嗎?
當(dāng)然不是,這樣不就影響了所有數(shù)組對(duì)象的原型鏈了么!
為了避免這種情況,且,我們只是想在監(jiān)聽(tīng)數(shù)據(jù)對(duì)象上繼承這些變異數(shù)組方法,那么細(xì)心的你會(huì)發(fā)現(xiàn),其實(shí)與我們?cè)?模擬Vue之?dāng)?shù)據(jù)驅(qū)動(dòng)3"中實(shí)現(xiàn)$set方法類(lèi)似了。
首先,我們創(chuàng)建arrKeys對(duì)象用于保存需要變異的數(shù)組方法以及恒定對(duì)象extendArr,如下:
let arrKeys = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']; const extendArr = [];
接著,就是在extendArr對(duì)象上,一一監(jiān)聽(tīng)arrKeys中的方法了,與$set方法類(lèi)似,整體結(jié)構(gòu)如下:
!function(){
arrKeys.forEach(function(key){
proxyObject(extendArr, key, function(){
//TODO
});
});
}();
注:proxyObject方法其實(shí)核心就是Object.defineProperty,詳見(jiàn)"模擬Vue之?dāng)?shù)據(jù)驅(qū)動(dòng)3".
接下來(lái),就是實(shí)現(xiàn)核心部分代碼了,重寫(xiě)這些方法的目的,是為了監(jiān)聽(tīng)數(shù)據(jù)變化,所以要在方法原有功能不變的情況下,重寫(xiě)它們,Array.xxx.apply即可實(shí)現(xiàn)原有功能。
且,push、unshift、splice這三個(gè)方法可以在原數(shù)組中,新增屬性,故而,我們需要監(jiān)聽(tīng)新增屬性以及它們的屬性值,這里就和$set方法完全一樣了,通過(guò)$Observer,即可利用observe以及convert方法實(shí)現(xiàn)了。
實(shí)現(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)聽(tīng)的對(duì)象上繼承這些變異方法咯,如下:
//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);
}
好了,一切完畢,接下來(lái)就測(cè)試下唄:
<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í),你可能會(huì)想,數(shù)組方法中僅有push、unshift、splice會(huì)為數(shù)組新增屬性,那么我們又何必將其他方法,例如sort、reverse重寫(xiě)呢,也沒(méi)發(fā)現(xiàn)有什么貓膩呢?
不錯(cuò),在此時(shí),并沒(méi)有什么卵用,但是,你要知道sort、reverse等這些方法,可是會(huì)引起數(shù)組變化的,那么就會(huì)影響視圖展現(xiàn),這些變化,又怎么通知數(shù)組呢?就是下篇隨筆會(huì)具體說(shuō)明的。
該篇隨筆代碼,詳情見(jiàn)github.
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Vue數(shù)據(jù)驅(qū)動(dòng)表單渲染,輕松搞定form表單
- 淺談vuejs實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)視圖原理
- 詳解VueJS 數(shù)據(jù)驅(qū)動(dòng)和依賴(lài)追蹤分析
- Vue數(shù)據(jù)驅(qū)動(dòng)模擬實(shí)現(xiàn)5
- Vue數(shù)據(jù)驅(qū)動(dòng)模擬實(shí)現(xiàn)2
- Vue數(shù)據(jù)驅(qū)動(dòng)模擬實(shí)現(xiàn)1
- Vue數(shù)據(jù)驅(qū)動(dòng)模擬實(shí)現(xiàn)3
- 詳解Vue數(shù)據(jù)驅(qū)動(dòng)原理
相關(guān)文章
UNIapp實(shí)現(xiàn)局域網(wǎng)內(nèi)在線升級(jí)的操作方法
這篇文章主要介紹了UNIapp實(shí)現(xiàn)局域網(wǎng)內(nèi)在線升級(jí)的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03
解決Vue.js 2.0 有時(shí)雙向綁定img src屬性失敗的問(wèn)題
下面小編就為大家分享一篇解決Vue.js 2.0 有時(shí)雙向綁定img src屬性失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
如何解決this.$refs.form.validate()不執(zhí)行的問(wèn)題
這篇文章主要介紹了如何解決this.$refs.form.validate()不執(zhí)行的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
vue和webpack項(xiàng)目構(gòu)建過(guò)程常用的npm命令詳解
本文通過(guò)實(shí)例代碼給大家介紹了vue和webpack項(xiàng)目構(gòu)建過(guò)程常用的npm命令,需要的朋友可以參考下2018-06-06
VUE3使用Element-Plus時(shí)如何修改ElMessage中的文字大小
在使用Element-plus的Elmessage時(shí)使用默認(rèn)的size無(wú)法滿足我們的需求時(shí),我們可以自定義字體的大小,但是直接重寫(xiě)樣式后,并沒(méi)有起作用,甚至使用::v-deep深度選擇器也沒(méi)有效果,本文介紹VUE3使用Element-Plus時(shí)如何修改ElMessage中的文字大小,感興趣的朋友一起看看吧2023-09-09
vue如何設(shè)置定時(shí)器和清理定時(shí)器
這篇文章主要介紹了vue如何設(shè)置定時(shí)器和清理定時(shí)器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
項(xiàng)目中Axios二次封裝實(shí)例Demo
vue項(xiàng)目經(jīng)常會(huì)用到axios來(lái)請(qǐng)求數(shù)據(jù),那么首先肯定需要對(duì)這個(gè)請(qǐng)求方法進(jìn)行一個(gè)二次封裝,這篇文章主要給大家介紹了關(guān)于項(xiàng)目中Axios二次封裝的相關(guān)資料,需要的朋友可以參考下2021-06-06
vue.js實(shí)現(xiàn)仿原生ios時(shí)間選擇組件實(shí)例代碼
本篇文章主要介紹了vue.js實(shí)現(xiàn)仿原生ios時(shí)間選擇組件實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2016-12-12
在vue中使用防抖和節(jié)流,防止重復(fù)點(diǎn)擊或重復(fù)上拉加載實(shí)例
今天小編就為大家分享一篇在vue中使用防抖和節(jié)流,防止重復(fù)點(diǎn)擊或重復(fù)上拉加載實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11

