一、概覽
- 用法:
在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。
- 疑問
- DOM 更新循環是指什么?
- 下次更新循環是什么時候?
- 修改數據之后使用,是加快了數據更新進度嗎?
- 在什么情況下要用到?
二、原理
1、異步說明
Vue 實現響應式並不是數據發生變化之后 DOM 立即變化,而是按一定的策略進行 DOM 的更新。
在 Vue 的文檔中,說明 Vue 是異步執行 DOM 更新的。
具體來說,異步執行的運行機制如下。
(1)所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。
(2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。
(3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,於是結束等待狀態,進入執行棧,開始執行。
(4)主線程不斷重復上面的第三步。
2、事件循環說明
簡單來說,Vue 在修改數據后,視圖不會立刻更新,而是等同一事件循環中的所有數據變化完成之后,再統一進行視圖更新。
知乎上的例子:
// 改變數據 vm.message = 'changed' // 想要立即使用更新后的DOM。這樣不行,因為設置message后DOM還沒有更新 console.log(vm.$el.textContent) // 並不會得到'changed' // 這樣可以,nextTick里面的代碼會在DOM更新后執行 Vue.nextTick(function(){ console.log(vm.$el.textContent) //可以得到'changed' })
三、用途
應用場景:需要在視圖更新之后,基於新的視圖進行操作。
1、created、mounted
需要注意的是,在 created 和 mounted 階段,如果需要操作渲染后的試圖,也要使用 nextTick 方法。
官方文檔說明:
注意 mounted 不會承諾所有的子組件也都一起被掛載。如果你希望等到整個視圖都渲染完畢,可以用 vm.$nextTick 替換掉 mounted。
mounted () { this.$nextTick(function () { // Code that will run only after the // entire view has been rendered }) }
2、其他應用場景
例子1:
點擊按鈕顯示原本以 v-show = false 隱藏起來的輸入框,並獲取焦點。
showsou(){ this.showit = true // 修改 v-show document.getElementById("keywords").focus() // 在第一個 tick 里,獲取不到輸入框,自然也獲取不到焦點 }
修改為:
showsou(){ this.showit = true this.$nextTick(function () { // DOM 更新了 document.getElementById("keywords").focus() }) }
例子2:
點擊獲取元素寬度。
<div id="app"> <p ref="myWidth" v-if="showMe">{{ message }}</p> <button @click="getMyWidth">獲取p元素寬度</button> </div> getMyWidth() { this.showMe = true; // this.message = this.$refs.myWidth.offsetWidth; // 報錯 TypeError: this.$refs.myWidth is undefined this.$nextTick(()=>{ // dom元素更新后執行,此時能拿到p元素的屬性 this.message = this.$refs.myWidth.offsetWidth; }) }