遇到這個方法的時候,比較困惑,搜集一些資料,總結一下其原理和用途
官網說法:在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。
獲取更新后的DOM,言外之意就是什么操作需要用到了更新后的DOM,
而不能使用之前的DOM,
所以就衍生出了這個獲取更新后的 DOM的Vue方法
DOM是如何更新的呢?
1.原理
Vue實現響應式並不是數據發生變化之后DOM立即變化,而是異步執行DOM更新的。
異步執行的運行機制是什么樣的?阮一峰老師是這樣總結的:
(1)所有同步任務都在主線程上執行,形成一個執行棧(execution context stack)。 (2)主線程之外,還存在一個"任務隊列"(task queue)。只要異步任務有了運行結果,就在"任務隊列"之中放置一個事件。 (3)一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務隊列",看看里面有哪些事件。那些對應的異步任務,於是結束等待狀態,進入執行棧,開始執行。 (4)主線程不斷重復上面的第三步。
主線程不斷執行任務、獲取任務、執行任務……的過程叫做事件循環
vue異步更新的原理:
1.修改 Vue 中的 Data 時,就會觸發所有和這個 Data 相關的 Watcher 進行更新。
2.首先,會將所有的 Watcher 加入隊列 Queue。
3.然后,調用 nextTick 方法,執行異步任務。
4.在異步任務的回調中,對 Queue 中的 Watcher 進行排序,然后執行對應的 DOM 更新。
// 當一個 Data 更新時,會依次執行以下代碼 // 1. 觸發 Data.set // 2. 調用 dep.notify 訂閱者 // 3. Dep 會遍歷所有相關的 Watcher 執行 update 方法 class Watcher { // 4. 執行更新操作 update() { queueWatcher(this); } } const queue = []; function queueWatcher(watcher: Watcher) { // 5. 將當前 Watcher 添加到異步隊列 queue.push(watcher); // 6. 執行異步隊列,並傳入回調 nextTick(flushSchedulerQueue); } // 更新視圖的具體方法 function flushSchedulerQueue() { let watcher, id; // 排序,先渲染父節點,再渲染子節點 // 這樣可以避免不必要的子節點渲染,如:父節點中 v-if 為 false 的子節點,就不用渲染了 queue.sort((a, b) => a.id - b.id); // 遍歷所有 Watcher 進行批量更新。 for (index = 0; index < queue.length; index++) { watcher = queue[index]; // 更新 DOM watcher.run(); } }
2.this.$nextTick()的使用場景
什么時候需要用Vue.nextTick():
- 在Vue生命周期的created()鈎子函數進行的DOM操作一定要放在Vue.nextTick()的回調函數中。原因是在created()鈎子函數執行的時候DOM 其實並未進行任何渲染,而此時進行DOM操作無異於徒勞,所以此處一定要將DOM操作的js代碼放進Vue.nextTick()的回調函數中。與之對應的就是mounted鈎子函數,因為該鈎子函數執行時所有的DOM掛載和渲染都已完成,此時在該鈎子函數中進行任何DOM操作都不會有問題 。
- 在數據變化后要執行的某個操作,當你設置 vm.someData = ‘new value’,DOM並不會馬上更新,而是在異步隊列被清除,也就是下一個事件循環開始時執行更新時才會進行必要的DOM更新。如果此時你想要根據更新的 DOM 狀態去做某些事情,就會出現問題。。為了在數據變化之后等待 Vue 完成更新 DOM ,可以在數據變化之后立即使用 Vue.nextTick(callback) 。這樣回調函數在 DOM 更新完成后就會調用。
- mounted 不會承諾所有的子組件也都一起被掛載。如果你希望等到整個視圖都渲染完畢,可以用 vm.$nextTick 替換掉 mounted
參考---https://www.icode9.com/content-4-816250.html
參考---https://www.jianshu.com/p/46c9d777cab1
參考---https://www.cnblogs.com/pleaseAnswer/p/13566987.html
