<强> 1。什么是Vue.nextTick () ?
强>
官方文档解释如下:
在下次DOM更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。
<强> 2。为什么要使用nextTick& # 63; 强>
& lt; !DOCTYPE html> & lt; html> & lt; head> & lt; title>演示Vue & lt;脚本src=" https://tugenhua0707.github.io/vue/vue1/vue.js "祝辞& lt;/script> & lt;/head> & lt; body> & lt; div id=坝τ谩北? & lt; template> & lt; div ref=傲斜怼北? {{名称}} & lt;/div> & lt;/template> & lt;/div> & lt; script> 新Vue ({ 埃尔:“#应用”, 数据:{ 名称:“aa” }, 安装(){ this.updateData (); }, 方法:{ updateData () { var自我=; this.name=癰b”; console.log(这一点。el.textContent美元);//aa 美元。nextTick(函数(){ console.log(自我。el.textContent美元);//bb }); } } }); & lt;/script> & lt;/body> & lt;/html> >之前如上代码在页面视图上显示bb,但是当我在控制台打印的时候,获取的文本内容还是aa,但是使用nextTick后,获取的文本内容就是最新的内容bb了,因此在这种情况下,我们可以使用nextTick函数了。
上面的代码为什么改变this.name=癰b”;后,再使用console.log(这一点。el.textContent美元);打印的值还是aa呢?那是因为设置名称的值后,DOM还没有更新到,所以获取值还是之前的值,但是我们放到nextTick函数里面的时候,代码会在DOM更新后执行,因此DOM更新后,再去获取元素的值就可以获取到最新值了。
理解DOM更新:在VUE中,当我们修改了数据中的某一个值后,并不会立即反应到该el中VUE将对更改的数据放到观察者的一个异步队列中,只有在当前任务空闲时才会执行观察家队列任务,这就有一个延迟时间,因此放到nextTick函数后就可以获取该el的最新值了。如果我们把上面的nextTick改成setTimeout也是可以的。
<强> 3。Vue源码详解之nextTick(源码在Vue/src/核心/util/js) 强>
在理解nextTick源码之前,我们先来理解下html5中新增的MutationObserver的API,它的作用是用来监听DOM变动的接口,它能监听一个DOM对象发生的子节点删除,属性修改,文本内容修改等等。
nextTick源码如下:
出口const nextTick=(函数(){ const回调=[] 让等待=false 让timerFunc 函数nextTickHandler () { 等待=false;/* 之所以要片复制一份出来是因为有的cb执行过程中又会往回调中加入内容,比如nextTick美元的回调函数里又有nextTick美元, 那么这些应该放入到下一个轮次的nextTick去执行,所以拷贝一份,遍历完成即可,防止一直循环下去。 */const=callbacks.slice副本(0) 回调。长度=0 (让我=0;我& lt;copies.length;我+ +){ 副本(我)() } }//nextTick行为利用了microtask队列,可以访问//通过本机的承诺。然后或MutationObserver。//MutationObserver更广泛的支持,然而它是严重困扰着//UIWebView iOS祝辞=9.3.3事件处理程序触发后联系。它//触发后完全停止工作几次……所以,如果本地//保证可用,我们将使用它: 如果*//*伊斯坦布尔忽略/* nextTick行为利用了microtask队列,先使用Promise.resolve () (nextTickHandler)来将异步回调 放入到microtask中,承诺和MutationObserver都可以使用,但是MutationObserver在IOS9.3以上的 WebView中有错误,因此如果满足第一项的话就可以执行,如果没有原生承诺就用MutationObserver。 */如果(typeof承诺!==ㄒ濉?,isNative(承诺)){ var p=Promise.resolve () var logError=呃=比;{console.error (err)} timerFunc=()=比;{ p.then (nextTickHandler) .catch (logError)//问题uiwebview,承诺。然后不完全打破,但是//可以陷入一种奇怪的状态回调是推入//microtask队列的队列没有被刷新,直到浏览器//需要做一些其他的工作,如处理一个计时器。因此,我们可以//刷新的“力”microtask队列添加一个空计时器。 如果isIOS setTimeout(等待) } }else if (typeof MutationObserver !==ㄒ濉?,( isNative (MutationObserver) | |//PhantomJS和iOS 7. x MutationObserver.toString()==='[对象MutationObserverConstructor]” )){//使用MutationObserver原生承诺不可用,//例如PhantomJS IE11 iOS7, Android 4.4/* 创建一个MutationObserver,观察监听到DOM改动之后执行的回调nextTickHandler */var counter=1 var观察者=new MutationObserver (nextTickHandler) var textNode=document.createTextNode (String(柜台));//使用MutationObserver的接口,监听文本节点的字符内容 观察者。观察(textNode, { characterData:真 });/* 每次执行timerFunc函数都会让文本节点的内容在0/1之间切换,切换之后将新赋值到那个我们MutationObserver监听的文本节点上去。 */timerFunc=()=比;{ counter=(计数器+ 1)% 2 textNode。data=https://www.yisu.com/zixun/String(柜台) } 其他}{//回退setTimeout/* 如果上面的两种都不支持的话,我们就使用setTimeout来执行 */timerFunc=()=> { setTimeout (nextTickHandler, 0) } } 返回函数queueNextTick (cb吗?:函数,ctx吗?:对象){ 让_resolve callbacks.push (()=> { 如果(cb) { 尝试{ cb.call (ctx) }捕捉(e) { handleError (e、ctx、“nextTick”) } }else if (_resolve) { _resolve (ctx) } });/*如果等待为真的,表明本轮事件循环中已经执行过timerFunc (nextTickHandler,0) */如果(待定){ 等待=true timerFunc () } 如果(!cb,,typeof承诺!==ㄒ濉?{ 返回新的承诺((解决,拒绝)=比;{ _resolve=解决 }) } } })()Vue中之nextTick函数源码分析详解