当前位置: 首页 > Web前端 > vue.js

vue.$nextTick使用

时间:2023-03-31 15:59:22 vue.js

vue.$nextTick使用Preface在做一个使用v-if控制输入隐藏显示的功能时,显示后需要设置输入焦点,但是ref设置焦点时,结果未定义。查找资料后发现是打开输入后立即查看数据造成的。也就是说,当显示输入打开时,Vue并不会立即更新dom数据,而是先将这个操作放入一个队列中;如果我们重复执行,队列也会进去重复操作;等在同一个事件循环中,所有数据更改完成后,处理队列中的数据。为了在数据更新操作后操作dom,可以在数据变化后立即使用vue.$nextTick,这样回调函数会在DOM更新完成后被调用,可以得到最新的DOM元素。看懂$nextTickvue官方文档的解释:在下一个DOM更新周期结束后执行延迟回调。修改数据后立即使用此方法获取更新后的DOM。简单的理解就是:当dom中有数据更新和渲染时,自动执行该函数。会用到的小知识点Macrotask(宏任务)主要代码块、setTimeout、setInterval、setImmediate、MessageChannel、postMessagemicrotask(微任务)promise、MutationObserver任务执行顺序和渲染执行macrotask->microtask->rendering->macrotask->microtask->rendering->......源码分析constcallbacks=[]letpending=falselettimerFuncexportfunctionnextTick(cb?:Function,ctx?:Object){let_resolvecallbacks.push(()=>{if(cb){try{cb.call(ctx)}catch(e){handleError(e,ctx,'nextTick')}}elseif(_resolve){_resolve(ctx)}})if(!pending){pending=truetimerFunc()}//$flow-disable-lineif(!cb&&typeofPromise!=='undefined'){returnnewPromise(resolve=>{_resolve=resolve})}}来自这个来源,你可以看到它基本上做的事件就是在nextTick的外层定义变量形成一个闭包,所以我们每次调用$nextTick其实就是添加回调函数的过程回调。callbacks添加新的回调函数后,执行timerFunc函数,pending用于表示同一时间只能执行一次。那么这个timerFunc函数是用来做什么的呢?我们继续看代码:exportletisUsingMicroTask=falseif(typeofPromise!=='undefined'&&isNative(Promise)){//判断一:是否原生支持Promiseconstp=Promise.resolve()timerFunc=()=>{p.then(flushCallbacks)if(isIOS)setTimeout(noop)}isUsingMicroTask=true}elseif(!isIE&&typeofMutationObserver!=='undefined'&&(isNative(MutationObserver)||MutationObserver.toString()==='[objectMutationObserverConstructor]')){//判断2:是否原生支持MutationObserverletcounter=1constobserver=newMutationObserver(flushCallbacks)consttextNode=document.createTextNode(String(counter))observer.observe(textNode,{characterData:true})timerFunc=()=>{counter=(counter+1)%2textNode.data=String(counter)}isUsingMicroTask=true}elseif(typeofsetImmediate!=='undefined'&&isNative(setImmediate)){//判断3:是否原生支持setImmediatetimerFunc=()=>{setImmediate(flushCallbacks)}}else{//判断4:以上都不行,使用setTimeouttimerFunc=()=>{setTimeout(flushCallbacks,0)}}这里有几个isNative函数判断传入的参数是否是它在当前环境中原生支持。可以看到做了四个判断,当前环境在不断的退化。尽量使用原生的Promise.then、MutationObserver和setImmediate,以上三者都不支持final使用setTimeout;降级过程的目的是将flushCallbacks函数放入microtask(判断1和判断2)或macrotask(判断3和判断4)中,等待下一个事件循环执行。MutationObserver是Html5的新特性,用于监测目标DOM结构是否发生变化,即代码中新建的textNode;如果发生变化,则执行MutationObserver构造函数中的回调函数,但它是在微任务中执行的。终于,终于找到我们终于需要的flushCallbacks函数了]()}}做的事情也很简单,复制callbacks数组,然后将callbacks置空,最后依次执行复制的数组中的各个函数;所以它的功能只是用来执行callbacks中的回调函数。综上,整个nextTick代码分析完毕,总结其流程:将回调函数放入callbacks等待执行将执行函数放入microtask或macrotask事件循环到microtask或macrotask,然后执行函数在回调中依次执行本文回调自引用