1. 程式人生 > 其它 >vue中的非同步更新佇列和$nextTick的使用

vue中的非同步更新佇列和$nextTick的使用

技術標籤:vuevue佇列nextTick

文章目錄


一、前言

我們先來看這樣一個場景:有一個div,預設用 v-if 將它隱藏,點選一個按鈕後,改變 v-if 的值,讓它顯示出來,同時拿到這個div的文字內容。如果一開始 v-if 的值是false,直接去獲取 div的內容是獲取不到的,因為此時 div還沒有被創建出來,那麼應該在點選按鈕後,改變 v-if 的值為 true,div才會被建立,此時再去獲取,示例程式碼如下:

<div id="app">
  <div id="div"
v-if="isShow">
我是一段內容</div> <button @click="getText">獲取div中的內容</button> </div> <script> let vm = new Vue({ el: "#app", data: { isShow: false }, methods: { getText() { this.isShow = true; let text =
document.getElementById('div').textContent; console.log(text); } } });
</script>

但是執行之後控制檯報錯了:
在這裡插入圖片描述
意思就是獲取不到 div 元素(document.getElementById('div')的結果是 null )。這裡就涉及 Vue 一個重要的概念:非同步更新佇列


二、非同步更新佇列

Vue並不是在資料發生變化之後立即更新 DOM,而是按一定的策略進行 DOM 的更新。

Vue 在更新 DOM 時是非同步執行的。只要偵聽到資料變化,Vue 將開啟一個佇列,並緩衝在同一事件迴圈中發生的所有資料變更。如果同一個 watcher 被多次觸發,只會被推入到佇列中一次。這種在緩衝時去除重複資料對於避免不必要的計算和 DOM 操作是非常重要的。然後,在下一個的事件迴圈“tick”中,Vue 重新整理佇列並執行實際 (已去重的) 工作。

所以如果我們用一個 for 迴圈來動態改變資料 100次,其實它只會應用最後一次改變,如果沒有這種機制, DOM 就要重繪100次,這固然是一個很大的開銷。

Vue 在內部對非同步佇列嘗試使用原生的 Promise.then、 MutationObserversetImmediate,如果執行環境不支援,則會採用 setTimeout(fn, 0) 代替。

例如,當我們設定 vm.someData = 'new value',該元件不會立即重新渲染。當重新整理佇列時,元件會在下一個事件迴圈“tick”中更新。多數情況我們不需要關心這個過程,但是如果你想基於更新後的 DOM 狀態來做點什麼,這就可能會有些棘手。雖然 Vue.js 通常鼓勵開發人員使用“資料驅動”的方式思考,避免直接接觸 DOM,但是有時我們必須要這麼做。

為了在資料變化之後等待 Vue 完成更新 DOM,可以在資料變化之後立即使用 Vue.nextTick(callback)(全域性方法) 或者 vm.$nextTick( [callback] )(在元件內使用)。這樣回撥函式將在 DOM 更新完成後被呼叫。

所以我們可以把上邊的程式碼改為:

getText() {
  this.isShow = true;
  this.$nextTick(function () {
    let text = document.getElementById('div');
    console.log(text);
  })
}

在元件內使用 vm.$nextTick() 例項方法不需要全域性 Vue,並且回撥函式中的 this 將自動繫結到當前的 Vue 例項上


三、資料

深入響應式原理 — vue官網

nextTick的使用 | vue官網