国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > JavaScript > 正文

Vue中之nextTick函數(shù)源碼分析詳解

2024-05-06 15:25:37
字體:
供稿:網(wǎng)友

1. 什么是Vue.nextTick()?

官方文檔解釋如下:

在下次DOM更新循環(huán)結(jié)束之后執(zhí)行的延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個方法,獲取更新后的DOM。

2. 為什么要使用nextTick?

<!DOCTYPE html><html> <head> <title>演示Vue</title> <script src="https://tugenhua0707.github.io/vue/vue1/vue.js"></script> </head> <body> <div id="app">  <template>  <div ref="list">   {{name}}  </div>  </template> </div> <script>  new Vue({  el: '#app',  data: {   name: 'aa'  },  mounted() {   this.updateData();  },  methods: {   updateData() {   var self = this;   this.name = 'bb';   console.log(this.$el.textContent); // aa   this.$nextTick(function(){    console.log(self.$el.textContent); // bb   });   }  }  }); </script> </body></html>

如上代碼 在頁面視圖上顯示bb,但是當(dāng)我在控制臺打印的時候,獲取的文本內(nèi)容還是 aa,但是使用 nextTick后,獲取的文本內(nèi)容就是最新的內(nèi)容bb了,因此在這種情況下,我們可以使用nextTick函數(shù)了。

上面的代碼為什么改變this.name = 'bb';后,再使用console.log(this.$el.textContent);打印的值還是aa呢?那是因為設(shè)置name的值后,DOM還沒有更新到,所以獲取值還是之前的值,但是我們放到nextTick函數(shù)里面的時候,代碼會在DOM更新后執(zhí)行,因此DOM更新后,再去獲取元素的值就可以獲取到最新值了。

理解DOM更新:在VUE中,當(dāng)我們修改了data中的某一個值后,并不會立即反應(yīng)到該el中,vue將對更改的數(shù)據(jù)放到watcher的一個異步隊列中,只有在當(dāng)前任務(wù)空閑時才會執(zhí)行watcher隊列任務(wù),這就有一個延遲時間,因此放到 nextTick函數(shù)后就可以獲取該el的最新值了。如果我們把上面的nextTick改成setTimeout也是可以的。

3. Vue源碼詳解之nextTick(源碼在 vue/src/core/util/env.js)

在理解nextTick源碼之前,我們先來理解下 html5中新增的 MutationObserver的API,它的作用是用來監(jiān)聽DOM變動的接口,它能監(jiān)聽一個dom對象發(fā)生的子節(jié)點刪除,屬性修改,文本內(nèi)容修改等等。

nextTick源碼如下:

export const nextTick = (function () { const callbacks = [] let pending = false let timerFunc function nextTickHandler () { pending = false; /*  之所以要slice復(fù)制一份出來是因為有的cb執(zhí)行過程中又會往callbacks中加入內(nèi)容,比如$nextTick的回調(diào)函數(shù)里又有$nextTick,  那么這些應(yīng)該放入到下一個輪次的nextTick去執(zhí)行,所以拷貝一份,遍歷完成即可,防止一直循環(huán)下去。  */ const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) {  copies[i]() } } // the nextTick behavior leverages the microtask queue, which can be accessed // via either native Promise.then or MutationObserver. // MutationObserver has wider support, however it is seriously bugged in // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It // completely stops working after triggering a few times... so, if native // Promise is available, we will use it: /* istanbul ignore if */ /* nextTick行為利用了microtask隊列, 先使用 Promise.resolve().then(nextTickHandler)來將異步回調(diào) 放入到microtask中,Promise 和 MutationObserver都可以使用,但是 MutationObserver 在IOS9.3以上的 WebView中有bug,因此如果滿足第一項的話就可以執(zhí)行,如果沒有原生Promise就用 MutationObserver。 */ if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => {  p.then(nextTickHandler).catch(logError)  // 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 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 /*  創(chuàng)建一個MutationObserver,observe監(jiān)聽到DOM改動之后執(zhí)行的回調(diào) nextTickHandler   */ var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(String(counter)); // 使用MutationObserver的接口,監(jiān)聽文本節(jié)點的字符內(nèi)容 observer.observe(textNode, {  characterData: true }); /*  每次執(zhí)行timerFunc函數(shù)都會讓文本節(jié)點的內(nèi)容在0/1之間切換,切換之后將新賦值到那個我們MutationObserver監(jiān)聽的文本節(jié)點上去。  */ timerFunc = () => {  counter = (counter + 1) % 2  textNode.data = String(counter) } } else { // fallback to setTimeout /*  如果上面的兩種都不支持的話,我們就使用setTimeout來執(zhí)行  */ 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)  } }); /* 如果pending為true,表明本輪事件循環(huán)中已經(jīng)執(zhí)行過 timerFunc(nextTickHandler, 0) */ if (!pending) {  pending = true  timerFunc() } if (!cb && typeof Promise !== 'undefined') {  return new Promise((resolve, reject) => {  _resolve = resolve  }) } }})()            
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 庄浪县| 大港区| 应城市| 青龙| 布尔津县| 古交市| 洪泽县| 洪江市| 桑日县| 铁岭县| 平塘县| 文山县| 虞城县| 翼城县| 黄龙县| 顺义区| 开化县| 东山县| 镇雄县| 临朐县| 桃源县| 蒲江县| 锡林郭勒盟| 海口市| 云梦县| 四平市| 怀化市| 灵山县| 丽水市| 景德镇市| 定西市| 新昌县| 墨脱县| 通州区| 兰西县| 湖口县| 蒲城县| 承德县| 苗栗市| 紫阳县| 高州市|