Vue.js
核心團(tuán)隊(duì)已經(jīng)開始討論將在 Vue3 中改變的實(shí)現(xiàn)了。API 不會(huì)有變化,但響應(yīng)式機(jī)制將會(huì)有所不用。這意味著什么,對(duì)你來說有什么意義?
Vue 2 的響應(yīng)式
Vue.js 2 中的響應(yīng)式是通過 Object.defineProperty
方法定義 getter
和 setter
完成的。我們來把 Vue 中做的事情簡(jiǎn)化出一個(gè)版本。
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get:function(){
return value;
},
set:function(newValue){
if(value !== newValue){
value = newValue;
tellTheWorldIhaveChanged(); //somebody is watching!
}
}
});
使用形如這樣的結(jié)構(gòu),當(dāng)我們每次對(duì)屬性進(jìn)行更改時(shí),它都會(huì)去通知需要知道這里有變化的觀察者和依賴。這個(gè)屬性的設(shè)置(注:指 defineProperty
)是在我們的初始化模型(注:this.data
)和我們顯式調(diào)用 Vue.set/vm.$set
時(shí)工作的。
但是,通過這樣的設(shè)置使下面內(nèi)容需要額外處理:
1. 按索引更新數(shù)組元素
data(){
return {
names:[]
}
}
...
this.persons[0] = 'John Elway';
你很可能已經(jīng)意識(shí)到以上代碼不會(huì)觸發(fā)更新。事實(shí)上,Vue 詳細(xì)的指南 中明確地提到關(guān)于數(shù)組的警告。為啥會(huì)這樣呢?因?yàn)閿?shù)組的 setter
屬性無法攔截檢測(cè)通過索引的賦值。
一個(gè)處理辦法是使用 Vue.set
方法
Vue.set(this.names, 0, 'John Elway');
并且 Vue 也對(duì)一些數(shù)組方法做了足夠的包裝,我們可以直接使用 Array 方法直接更新數(shù)組對(duì)象。
this.names.push('John Elway');
2. 動(dòng)態(tài)添加屬性
data(){
return {
names:[]
}
}
...
this.$data.lastAddedName = 'John Elway';
這可能是最好的例子,對(duì)吧?我可能應(yīng)該知道某個(gè)屬性已經(jīng)存在,但有些情況下我們或許并不知道屬性名稱。
JavaScript 提供 loosed-typedness
允許我們輕松添加屬性。然而,Vue 響應(yīng)式并不清楚我們添加了什么。
放著我來! —— Vue.set
Vue.set(this.$data,'lastAddedName','John Elway');
如果我們能有一種避免所有 Vue.set
使用情況并把索引操作還給我們的方法.
Vue 3 的響應(yīng)式
Welcome to 通過代理 (Proxy) 實(shí)現(xiàn)響應(yīng)式的世界。
Proxy 是在 ES6 或者稱 ES2015 中引進(jìn)的特性,他們已經(jīng)出現(xiàn)一段時(shí)間,因此我確信大家已經(jīng)了解他們了,但可能不會(huì)在生產(chǎn)環(huán)境中使用。
因?yàn)?Proxy 也是無法shim 的特性,沒有 polyfill
,也無法在瀏覽器中 fake
實(shí)現(xiàn)。
幸運(yùn)的是,它的語法并不荒謬。事實(shí)上,他也算有些熟悉。
let data = {
names:[]
};
data.names = new Proxy(data.names,{
set:function(obj, prop, value){
if(obj[prop] !== value){
obj[prop] = value;
tellTheWorldIhaveChanged();
}
}
});
這里 proxy
不僅攔截前面提到的數(shù)組索引賦值,還會(huì)在調(diào)用數(shù)組方法時(shí)觸發(fā),不再需要包裝方法。
那么關(guān)于動(dòng)態(tài)添加屬性呢?
data = new Proxy(data,{
set:function(obj, prop, value){
if(obj[prop] !== value){
obj[prop] = value;
tellTheWorldIhaveChanged();
}
}
});
data.lastAddedName = 'John Elway'; //tellTheWorldIhaveChanged()
OMG. Awesome! 讓我們趕緊讓它快點(diǎn)發(fā)布吧!
總結(jié)
我在 Vue 2.5 發(fā)布之前就開始簡(jiǎn)短的寫了。Vue 3 并沒有被過多討論,但由于上面提到的變化,我真的很期待它。話雖如此,我還是無法在近期的工作項(xiàng)目中使用它。Why? Vue3 沒有對(duì) IE 的兼容性,Babel 也不能解決這個(gè)問題。
但是,這種重構(gòu)依然有長(zhǎng)期優(yōu)勢(shì):
- 簡(jiǎn)化源碼 - 這種重構(gòu)使得團(tuán)隊(duì)去掉數(shù)組方法包裝并減少需要做的類型檢查
- 新手更易上手 - 從響應(yīng)式中獲取的警告有助于 Vue 新手,這將消除社區(qū)論壇一整類的問題
- 更好的性能 - 我見到一些人們建議這樣做來提升響應(yīng)式的速度,它其實(shí)已經(jīng)非??炝?,我還沒在這一點(diǎn)上被說服
感謝閱讀!如果你發(fā)現(xiàn)了任何錯(cuò)誤,請(qǐng)聯(lián)系我.
2019-03-19 Update
似乎使用 Proxy
的版本將附加 -next
(像ES-next) 到當(dāng)前版本號(hào),而不是用 Vue 3。這種更新可能最早出現(xiàn)在 Vue 2.6 和 Vue2.6-next 中。這將消除對(duì) API 中可用內(nèi)容的混淆。
歡迎大家到公眾號(hào): you的日常
閱讀,體驗(yàn)更好哦。