我們已經(jīng)涵蓋了大部分的基礎(chǔ)知識,現(xiàn)在击纬,是時候深入底層原理了嘿歌!
Vue最顯著的特性之一便是不太引人注意的響應(yīng)式系統(tǒng)馍管。模型層(model)只是普通的js對象郭赐,修改它則更新視圖(view),這會讓狀態(tài)管理變得非常簡單且直觀
(一)如何追蹤變化确沸?
把一個普通的JS對象傳給Vue實例的data選項捌锭,Vue將會遍歷此對象的所有屬性,并使用 Object.defineProperty 把這些屬性全部轉(zhuǎn)為 getter/setter罗捎。Object.defineProperty 是僅 ES5 支持观谦,且無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器的原因桨菜。
每個組件實例都有相應(yīng)的watcher實例對象豁状,他會在組件渲染的過程中把屬性記錄為依賴捉偏,之后當依賴的setter被調(diào)用時,會通知watcher重新計算泻红,從而使它關(guān)聯(lián)的組件得以更新
(二)變化檢測問題
受現(xiàn)代 JavaScript 的限制(以及廢棄 Object.observe)夭禽,Vue 不能檢測到對象屬性的添加或刪除。由于 Vue 會在初始化實例時對屬性執(zhí)行 getter/setter 轉(zhuǎn)化過程谊路,所以屬性必須在 data 對象上存在才能讓 Vue 轉(zhuǎn)換它讹躯,這樣才能讓它是響應(yīng)的
比如:
var vm = new Vue({
data: {
a: 1
}
})
// vm.a是相應(yīng)的
vm.b = 2 // vm.b是非相應(yīng)的
解決方法:
1.Vue.set(vm.arr,1,'ddd')
2.vm.$set(vm.arr,1,'ddd')
(三)聲明響應(yīng)式屬性
由于Vue不允許動態(tài)添加根級響應(yīng)式屬性,所以你必須在初始化實例前聲明根級響應(yīng)式屬性缠劝,哪怕只是一個空值
var vm = new Vue({
el: '#app',
data: {
a: 1,
b: ''
}
})
這樣的限制在背后是有其技術(shù)原因的潮梯,它消除了在依賴項跟蹤系統(tǒng)中的一類邊界情況,也使 Vue 實例在類型檢查系統(tǒng)的幫助下運行的更高效惨恭。而且在代碼可維護性方面也有一點重要的考慮:data 對象就像組件狀態(tài)的概要酷麦,提前聲明所有的響應(yīng)式屬性,可以讓組件代碼在以后重新閱讀或其他開發(fā)人員閱讀時更易于被理解喉恋。
(四)異步更新隊列
為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM ,可以在數(shù)據(jù)變化之后立即使用 Vue.nextTick(callback) 母廷。這樣回調(diào)函數(shù)在 DOM 更新完成后就會調(diào)用
比如:
<div id="app">
<p>{{ a }}</p>
</div>
var vm = new Vue({
el: '#app',
data: {
a: 1
}
})
vm.a=10;
alert(vm.$el.textContent);
vm.$nextTick(function(){
alert(vm.$el.textContent)
})