1. 程式人生 > >Vue原始碼小問答二:Vue.nextTick的用法

Vue原始碼小問答二:Vue.nextTick的用法

Vue.nextTick

官方說明

在下次 DOM 更新迴圈結束之後執行延遲迴調。在修改資料之後立即使用這個方法,獲取更新後的 DOM。

註解

Vue的Dom樹更新一般是在非同步回撥中完成的,這裡的非同步回撥可能用promise或者setTimeout。這就導致我們無法以同步的方式獲取更新後的Dom結構,因為在資料狀態更新完成之後Vue並不是立即更新Dom樹,而是在下一個事件迴圈中更新。(不要問我問什麼要做非同步,文件裡說的很清楚)

Vue會在完成Dom更新後呼叫Vue.nextTick,所以這個可以獲取到更新後的Dom。

nextTick是一個全域性方法,也就是所有的Vue例項都會在統一的地方處理。這個方法主要是在資料狀態發生變化後呼叫,例如data

的變化、mutation呼叫之後等。例如頁面上有Vue例項a、b,js對這兩個例項的data進行修改後分別呼叫了vue.nextTick,在頁面完成dom更新後兩個回撥函式會以此被呼叫。

原始碼解毒:請看中文註釋部分

export const nextTick = (function () {
  // 存放一次dom更新迴圈內所有的回撥函式
  const callbacks = []
  // 在一次dom更新迴圈內timerFunc方法只能被呼叫一次
  let pending = false
  let timerFunc

  function nextTickHandler () {
pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } // 在eventloop大迴圈中插入回撥 if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) if
(isIOS) setTimeout(noop) } } else if (typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || // PhantomJS and iOS 7.x MutationObserver.toString() === '[object MutationObserverConstructor]' )) { // use MutationObserver where native Promise is not available, // e.g. PhantomJS IE11, iOS7, Android 4.4 var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(String(counter)) observer.observe(textNode, { characterData: true }) timerFunc = () => { counter = (counter + 1) % 2 textNode.data = String(counter) } } else { // fallback to setTimeout /* istanbul ignore next */ timerFunc = () => { setTimeout(nextTickHandler, 0) } } return function queueNextTick (cb?: Function, ctx?: Object) { let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== 'undefined') { return new Promise((resolve, reject) => { _resolve = resolve }) } } })()