成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Vue.nextTick淺析

MartinDai / 938人閱讀

摘要:淺析的特點之一就是響應式,但數(shù)據(jù)更新時,并不會立即更新。盡管已經(jīng)更新,但新增的元素并不立即插入到中。實際在中,執(zhí)行了,這也是自動綁定到執(zhí)行上下文的原因。在內,使用數(shù)組保存回調函數(shù),表示當前狀態(tài),使用函數(shù)來執(zhí)行回調隊列。

Vue.nextTick 淺析

Vue 的特點之一就是響應式,但數(shù)據(jù)更新時,DOM 并不會立即更新。當我們有一個業(yè)務場景,需要在 DOM 更新之后再執(zhí)行一段代碼時,可以借助nextTick實現(xiàn)。以下是來自官方文檔的介紹:

將回調延遲到下次 DOM 更新循環(huán)之后執(zhí)行。在修改數(shù)據(jù)之后立即使用它,然后等待 DOM 更新。

具體的使用場景和底層代碼實現(xiàn)在后面的段落說明和解釋。

用途

Vue.nextTick([callback, context])vm.$nextTick([callback])

前者是全局方法,可以顯式指定執(zhí)行上下文,而后者是實例方法,執(zhí)行時自動綁定this到當前實例上。

此外,在 2.1.0 版本還新增了不傳入回調的使用方式,這種調用會返回一個 Promise,在 then 的回調執(zhí)行目標操作即可,如vm.$nextTick().then(cb)。

以下是一個nextTick使用例子:

{{count}}
  • {{item}}
new Vue({
  el: "#app",
  data: {
    count: 0,
    list: []
  },
  methods: {
    add() {
      this.count += 1;
      this.list.push(1);
      let li = this.$refs.ul.querySelectorAll("li");
      li.forEach(item => {
        item.style.color = "red";
      });
    }
  }
});

以上的代碼,期望在每次新增一個列表項時都使得列表項的字體是紅色的,但實際上新增的列表項字體仍是黑色的。盡管data已經(jīng)更新,但新增的 li 元素并不立即插入到 DOM 中。如果希望在 DOM 更新后再更新樣式,可以在nextTick的回調中執(zhí)行更新樣式的操作。

new Vue({
  el: "#app",
  data: {
    count: 0,
    list: []
  },
  methods: {
    add() {
      this.count += 1;
      this.list.push(1);
      this.$nextTick(() => {
        let li = this.$refs.ul.querySelectorAll("li");
        li.forEach(item => {
          item.style.color = "red";
        });
      });
    }
  }
});
解釋

數(shù)據(jù)更新時,并不會立即更新 DOM。如果在更新數(shù)據(jù)之后的代碼執(zhí)行另一段代碼,有可能達不到預想效果。將視圖更新后的操作放在nextTick的回調中執(zhí)行,其底層通過微任務的方式執(zhí)行回調,可以保證 DOM 更新后才執(zhí)行代碼。

源碼

/src/core/instance/index.js,執(zhí)行方法renderMixin(Vue)Vue.prototype添加了$nextTick方法。實際在Vue.prototype.$nextTick中,執(zhí)行了nextTick(fn, this),這也是vm.$nextTick( [callback] )自動綁定this到執(zhí)行上下文的原因。

nextTick函數(shù)在/scr/core/util/next-tick.js聲明。在next-tick.js內,使用數(shù)組callbacks保存回調函數(shù),pending表示當前狀態(tài),使用函數(shù)flushCallbacks來執(zhí)行回調隊列。在該方法內,先通過slice(0)保存了回調隊列的一個副本,通過設置callbacks.length = 0清空回調隊列,最后使用循環(huán)執(zhí)行在副本里的所有函數(shù)。

const callbacks = [];
let pending = false;

function flushCallbacks() {
  pending = false;
  const copies = callbacks.slice(0);
  callbacks.length = 0;
  for (let i = 0; i < copies.length; i++) {
    copies[i]();
  }
}

接著定義函數(shù)marcoTimerFuncmicroTimerFunc。

先判斷是否支持setImmediate,如果支持,使用setImmediate執(zhí)行回調隊列;如果不支持,判斷是否支持MessageChannel,支持時,在port1監(jiān)聽message,將flushCallbacks作為回調;如果仍不支持MessageChannel,使用setTimeout(flushCallbacks, 0)執(zhí)行回調隊列。不管使用哪種方式,macroTimerFunc最終目的都是在一個宏任務里執(zhí)行回調隊列。

if (typeof setImmediate !== "undefined" && isNative(setImmediate)) {
  macroTimerFunc = () => {
    setImmediate(flushCallbacks);
  };
} else if (
  typeof MessageChannel !== "undefined" &&
  (isNative(MessageChannel) ||
    // PhantomJS
    MessageChannel.toString() === "[object MessageChannelConstructor]")
) {
  const channel = new MessageChannel();
  const port = channel.port2;
  channel.port1.onmessage = flushCallbacks;
  macroTimerFunc = () => {
    port.postMessage(1);
  };
} else {
  /* istanbul ignore next */
  macroTimerFunc = () => {
    setTimeout(flushCallbacks, 0);
  };
}

然后判斷是否支持Promise,支持時,新建一個狀態(tài)為resolvedPromise對象,并在then回調里執(zhí)行回調隊列,如此,便在一個微任務中執(zhí)行回調,在 IOS 的 UIWebViews 組件中,盡管能創(chuàng)建一個微任務,但這個隊列并不會執(zhí)行,除非瀏覽器需要執(zhí)行其他任務;所以使用setTimeout添加一個不執(zhí)行任何操作的回調,使得微任務隊列被執(zhí)行。如果不支持Promise,使用降級方案,將microTimerFunc指向macroTimerFunc。

if (typeof Promise !== "undefined" && isNative(Promise)) {
  const p = Promise.resolve();
  microTimerFunc = () => {
    p.then(flushCallbacks);
    // in problematic UIWebViews, Promise.then doesn"t completely break, but
    // it can get stuck in a weird state where callbacks are pushed into the
    // microtask queue but the queue isn"t being flushed, until the browser
    // needs to do some other work, e.g. handle a timer. Therefore we can
    // "force" the microtask queue to be flushed by adding an empty timer.
    if (isIOS) setTimeout(noop);
  };
} else {
  // fallback to macro
  microTimerFunc = macroTimerFunc;
}

在函數(shù)nextTick內,先將函數(shù)cb使用箭頭函數(shù)包裝起來并添加到回調隊列callbacks,轉入的回調cb會在callbacks被遍歷執(zhí)行的時候執(zhí)行。如果沒有傳入cb,則是形如this.$nextTick().then(cb)的使用方式,所以要返回一個fulfilled的 Promise,在箭頭函數(shù)內則需要執(zhí)行resolved,令返回的 Promise 狀態(tài)變?yōu)?b>fulfilled。接著判斷當前是否正在執(zhí)行回調,如果不是,將pengding設置為真。判斷回調執(zhí)行是宏任務還是微任務,分別通過marcoTimerFunc、microTimerFunc來觸發(fā)回調隊列。最后,如果,沒有傳入cb,則需要創(chuàng)建一個Promise實例并返回以支持鏈式調用,并且將_resolve指向返回 Promise 的resolve函數(shù)。

export function nextTick(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;
    if (useMacroTask) {
      macroTimerFunc();
    } else {
      microTimerFunc();
    }
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== "undefined") {
    return new Promise(resolve => {
      _resolve = resolve;
    });
  }
}

而全局方法Vue.nextTick/src/core/global-api/index.js中聲明,是對函數(shù)nextTick的引用,所以使用時可以顯式指定執(zhí)行上下文。

Vue.nextTick = nextTick;
小結

本文關于nextTick的使用場景和源碼做了簡單的介紹,如果想深入了解這部分的知識,可以去了解一下微任務mircotask和宏任務marcotask。

文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://systransis.cn/yun/108549.html

相關文章

  • 淺析 Vue 2.6 中的 nextTick 方法

    摘要:核心的異步延遲函數(shù),用于異步延遲調用函數(shù)優(yōu)先使用原生原本支持更廣,但在的中,觸摸事件處理程序中觸發(fā)會產(chǎn)生嚴重錯誤的,回調被推入隊列但是隊列可能不會如期執(zhí)行。 淺析 Vue 2.6 中的 nextTick 方法。 事件循環(huán) JS 的 事件循環(huán) 和 任務隊列 其實是理解 nextTick 概念的關鍵。這個網(wǎng)上其實有很多優(yōu)質的文章做了詳細介紹,我就簡單過過了。 以下內容適用于瀏覽器端 JS,...

    fobnn 評論0 收藏0
  • 前方來報,八月最新資訊--關于vue2&3的最佳文章推薦

    摘要:哪吒別人的看法都是狗屁,你是誰只有你自己說了才算,這是爹教我的道理。哪吒去他個鳥命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰和你做朋友太乙真人人是否能夠改變命運,我不曉得。我只曉得,不認命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...

    izhuhaodev 評論0 收藏0
  • 詳細分析Vue.nextTick()實現(xiàn)

    摘要:因為平時使用都是傳回調的,所以很好奇什么情況下會為,去翻看官方文檔發(fā)現(xiàn)起新增如果沒有提供回調且在支持的環(huán)境中,則返回一個。這就對了,函數(shù)體內最后的判斷很明顯就是這個意思沒有回調支持。 Firstly, this paper is based on Vue 2.6.8剛開始接觸Vue的時候,哇nextTick好強,咋就在這里面寫就是dom更新之后,當時連什么macrotask、micro...

    DevYK 評論0 收藏0
  • Vue.nextTick 的原理和用途

    摘要:在查詢了各種資料后,總結了一下其原理和用途,如有錯誤,請不吝賜教。截取關鍵部分如下具體來說,異步執(zhí)行的運行機制如下。知乎上的例子改變數(shù)據(jù)想要立即使用更新后的。需要注意的是,在和階段,如果需要操作渲染后的試圖,也要使用方法。 對于 Vue.nextTick 方法,自己有些疑惑。在查詢了各種資料后,總結了一下其原理和用途,如有錯誤,請不吝賜教。 概覽 官方文檔說明: 用法: 在下次 DO...

    fevin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<