vue響應(yīng)原理

Copy自

官方文檔

如何追蹤變化

Vue會遍歷data選項中的所有屬性,并使用Object.defineProperty把這些屬性全部轉(zhuǎn)化為getter/setter。
Object.defineProperty是ES5中一個無法優(yōu)雅降級的特性,這也是Vue不支持IE8及更低版本瀏覽器的原因。

這些getter/setter對用戶來說是不可見的,但是它們讓Vue能夠追蹤依賴,在屬性被訪問和修改時通過getter/setter來通知變更。

每個組件實例都對應(yīng)一個watcher實例,它會在組件渲染的過程中把“接觸”過的數(shù)據(jù)屬性記錄為依賴。之后當(dāng)依賴項的setter觸發(fā)時,會通知watcher,從而使它關(guān)聯(lián)的組件重新渲染。

檢測變化的注意事項

受現(xiàn)代JavaScript的限制,Vue無法檢測到對象屬性的添加或刪除。
Vue會在初始化實例時對屬性執(zhí)行getter/setter轉(zhuǎn)化,所以屬性必須一開始就得在data對象上存在才能讓Vue用Object.defineProperty將它轉(zhuǎn)化為響應(yīng)式的。列如:

<div>
    <span v-for="(item, index) in obj" :key="index">{{item}}</span>
    <button @click="addObj">添加屬性</button> // 
</div>
data() {
    return {
        obj: {
            a:1 // 響應(yīng)式屬性
        }
    }
},
methods: {
    addObj() {
        this.obj.b = 2 // 非響應(yīng)式屬性
    }
},

上面的代碼希望調(diào)用addObj方法向this.obj添加屬性并且視圖能夠更新。失?。⌒枰蝽憫?yīng)式對象添加屬性應(yīng)該用Vue.set()方法才能將添加的屬性變?yōu)轫憫?yīng)式的。
對于已經(jīng)創(chuàng)建的實例,Vue不允許動態(tài)添加根級別的響應(yīng)式屬性。但是,Vue提供了Vue.set(obj, propertyName, value)方法向嵌套對象添加響應(yīng)式屬性。列如:

this.$set(this.obj, 'b', 2)

需要為已有對象賦值多個新屬性時應(yīng)該用原對象與要混合進(jìn)去的對象的新屬性一起創(chuàng)建一個新對象:

this.obj = Object.assign({}, this.obj, {c: 3, d: 4})

異步更新隊列

Vue在更新DOM時是異步執(zhí)行的。只要偵聽到數(shù)據(jù)的變化,Vue將開啟一個隊列,并緩沖 在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。如果同一個watcher被多次觸發(fā),只會被推入到隊列中一次。這種在緩沖時去除重復(fù)數(shù)據(jù)對于避免不必要的計算和DOM操作非常重要。然后,在下一個事件循環(huán)tick中,Vue刷新隊列并執(zhí)行實際工作。Vue在內(nèi)部對異步隊列嘗試使用原生的Promise.then、MutationObserversetTimeOut,如果執(zhí)行環(huán)境不支持,則會采用setTimeOut(fn, 0)代替。
為了在數(shù)據(jù)變化之后等待Vue完成更新DOM,可以在數(shù)據(jù)變化后立即使用Vue.nextTick(callback)。這樣回調(diào)函數(shù)將在DOM更新完后被調(diào)用。
nextTick()返回一個Promise對象,所以可以使用async/await語法:

async function () {
    <!-- DOM未更新 -->
    await this.$nextTick()
    <!-- DOM已更新 -->
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容