基本認(rèn)識(shí)
- 作用:Vue 會(huì)遞歸將 data 的屬性轉(zhuǎn)換為 getter/setter 方法,從而使得 data 中屬性能夠響應(yīng)數(shù)據(jù)變化。
- 類型: Object | Function
// Object 類型 data 屬性
const vm = new Vue({
data: {
name: 'IT白'
}
})
// Function 類型 data 屬性
const component = Vue.extend({
template: '<p>My name is {{ name }}</p>',
data: function () {
return {
name: 'IT白',
}
}
})
創(chuàng)建 Object 類型與 Function 類型的data屬性的異同
- 相同點(diǎn):Vue 都會(huì)為其生成相應(yīng)的 getter/setter 方法。
- 不同點(diǎn):當(dāng)組件被同一時(shí)間多次實(shí)例化時(shí)
??Object 類型:組件的所有實(shí)例都會(huì)引用同一個(gè)數(shù)據(jù)對(duì)象。當(dāng)一個(gè)實(shí)例修改的自身的 data 屬性,由于引用統(tǒng)一個(gè)數(shù)據(jù)對(duì)象,導(dǎo)致修改也將會(huì)在其它實(shí)例中呈現(xiàn)。
??Function 類型:每次創(chuàng)建組件實(shí)例時(shí), Vue 都將通過(guò)調(diào)用該函數(shù),創(chuàng)建一個(gè)全新副本的數(shù)據(jù)對(duì)象。當(dāng)一個(gè)實(shí)例修改自身的 data 屬性,由于每個(gè)實(shí)例中的 data 屬性對(duì)象都是單獨(dú)的副本,所以不會(huì)影響其它實(shí)例。
注:如果將組件的 data 屬性定義為 Object 類型,Vue 會(huì)拋出警告。
data 屬性響應(yīng)式原理
追蹤數(shù)據(jù)變化
- 準(zhǔn)備:Vue 會(huì)遍歷 data 對(duì)象(如果是 Function 類型,Vue 會(huì)先調(diào)用函數(shù),創(chuàng)建對(duì)應(yīng)對(duì)象),并將所有屬性通過(guò)
Object.defineProperty()轉(zhuǎn)換成getter/setter。 - collect as dependency:每個(gè)組件實(shí)例都對(duì)應(yīng)一個(gè) watcher 實(shí)例,它會(huì)在組件渲染的過(guò)程中把“接觸”過(guò)的數(shù)據(jù)屬性記錄為依賴。
- notify:當(dāng) setter 被觸發(fā)時(shí),會(huì)通知 watcher。
- trigger re-render:watcher 重新渲染關(guān)聯(lián)的組件。
- touch:如果實(shí)例修改 data 屬性的值,將會(huì)觸發(fā) setter。

檢測(cè)變化的注意事項(xiàng)
由于 JavaScript 的限制,Vue 無(wú)法檢測(cè)對(duì)象屬性的添加或刪除,所以直接動(dòng)態(tài)添加屬性到 data 對(duì)象中,該屬性為非響應(yīng)式。
var vm = new Vue({
data:{
a:1
}
})
// `vm.a` 是響應(yīng)式的
vm.b = 2
// `vm.b` 是非響應(yīng)式的
但是可以通過(guò) Vue.set(object, propertyName, value) 方法向嵌套對(duì)象添加響應(yīng)式屬性,以及 Object.assign() 方法創(chuàng)建一個(gè)新的對(duì)象。
Vue.set(vm.someObject, 'b', 2)
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
異步更新隊(duì)列
Vue 在更新 DOM 時(shí)是異步執(zhí)行的。
??只要偵聽(tīng)到數(shù)據(jù)變化,Vue 將開(kāi)啟一個(gè)隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。
??如果同一個(gè) watcher 被多次觸發(fā),只會(huì)被推入到隊(duì)列中一次。這種在緩沖時(shí)去除重復(fù)數(shù)據(jù)對(duì)于避免不必要的計(jì)算和 DOM 操作是非常重要的。然后,在下一個(gè)的事件循環(huán)“tick”中,Vue 刷新隊(duì)列并執(zhí)行實(shí)際 (已去重的) 工作。
??Vue 在內(nèi)部對(duì)異步隊(duì)列嘗試使用原生的Promise.then、MutationObserver和setImmediate,如果執(zhí)行環(huán)境不支持,則會(huì)采用setTimeout(fn, 0)代替。使用
.nextTick()。
??為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM,可以在數(shù)據(jù)變化之后立即使用Vue.nextTick(callback)。這樣回調(diào)函數(shù)將在 DOM 更新完成后被調(diào)用。