Nous sommes presque en 2023, vous ne le savez pas encore.$nextTick ? Vue2 est sorti depuis près de 10 ans, et Vue3 est sorti depuis plus de deux ans, c'est vrai ! C'est embarrassant de le dire. Je ne connais que this.nextTick maintenant (à vrai dire). D'accord, cherchons-le d'abord sur Baidu, cliquez sur cliquez... J'ai rapidement sauté sur le document du site officiel de Vue.js et j'ai soudainement trouvé un. phrase dans le document ? :
nextTick : Exécuter un rappel différé après la fin de la prochaine boucle de mise à jour du DOM. Utilisez cette méthode immédiatement après avoir modifié les données pour obtenir le DOM mis à jour. Il a deux paramètres : le premier paramètre est
fonction de rappel
, qui fournit un appel de promesse s'il n'est pas transmis ; le deuxième paramètre estcontexte d'environnement d'exécution
, qui par défaut est une liaison automatique s'il n'est pas transmis ; . est affecté à l'instance qui l'appelle. [Recommandations associées : tutoriel vidéo vuejs, développement web front-end]回调函数
,不传时提供promise调用;第二个参数是执行环境上下文
,不传默认是自动绑定到调用它的实例上。【相关推荐:vuejs视频教程、web前端开发】
我们先看看nextTick究竟是个啥?
console.log(this.$nextTick); // 控制台打印 if(fn){ return nextTick(fn, this); }
我们可以看出nextTick就是一个方法,方法有两个参数:fn和this,fn就是需要传的回调函数,this就是所说的执行环境上下文。那么问题来了,在Vue中是如何实现在下一次DOM更新结束之后才会执行延迟回调的? 我们先看看下面的例子:
<div ref="test1">created:{{message}}</div> // vue实例 data: { message: "Hello World!", }, created(){ this.message = '你好,世界!'; console.log(this.$refs.test1.innerText);// 报错 // TypeError: Cannot read properties of undefined (reading 'innerText') this.$nextTick(()=>{ console.log('test1 nextTick:',this.$refs.test1.innerText);// 你好,世界! }); },
从上面例子中,在created生命周期中操作了DOM,但是我们都知道created生命周期只是初始化了数据,这期间是还没有渲染DOM的,如果我们直接操作DOM是找不到DOM元素的,那么问题来了:为什么放在nextTick中就可以获取到了DOM元素呢? 这不是很明显吗,等到DOM渲染完才调用不就获取到了吗,从而知道了nextTick作用就是用来等下次DOM渲染完才去调用nextTick内的DOM操作代码
console.log('同步代码1'); setTimeout(function () { console.log("setTimeout"); }, 0); new Promise((resolve) => { console.log('同步代码2') resolve() }).then(() => { console.log('promise.then') }) console.log('同步代码3');
this est ce qu'on appelle le contexte d'environnement d'exécution. La question est donc : Comment implémenter un rappel différé dans Vue jusqu'à ce que la prochaine mise à jour du DOM soit terminée ? Jetons d'abord un coup d'œil à l'exemple suivant :
// 同步代码1 // 同步代码2 // 同步代码3 // promise.then // setTimeout
nextTick est d'attendre la prochaine fois que le DOM est rendu avant d'appeler l'opération DOM. code dans nextTick
. La question revient donc : que fait exactement nextTick ? Analysons le principe nextTick des versions Vue2 et Vue3 depuis le niveau du code source. Version Vue2 de nextTick, exécution retardée de la fonction de rappel
,用来监听DOM的变动
,比如节点的增减、属性的变动、文本内容的修改等都会触发MutationObserver事件。注意地,与事件不同,事件是同步触发,DOM的变动会立即触发事件,而MutationObserver事件是异步触发,DOM不会立即触发,需要等当前所有DOM操作完毕才会触发。MutationObserver有7个属性:
childList
(true,监听子节点的变动)、attributes
(true,监听属性的变动)、characterData
(true,监听节点内容或节点文本的变动)、subtree
(是否应用于该节点的所有后代节点)、attributeOldValue
(观察attributes变动时,是否需要记录变动前的属性值)、characterDataOldValue
(观察characterData变动时,是否需要记录变动前的值)、attributeFilter
(数组,表示需要观察的特定属性(比如[‘class’,‘src’])。
为什么需要创建一个文本节点?因为在这里操作DOM保证浏览器页面是最新DOM渲染的,虽然看来好像是没什么作用,但这是保证拿到的DOM是最新的。
支持setImmediate、setTimeout,setImmediate即时计时器立即执行工作,它是在事件轮询之后执行,为了防止轮询阻塞,每次只会调用一个。setTimeout按照一定时间后执行回调函数。
好了好了,到了现在,我们都知道nextTick做了什么吧,但是我们有没有想过这样的一个问题:既然都是异步回调执行等待DOM更新后才去调用操作DOM的代码,那么这个机制又是什么原理?这就是JS的执行机制有关了,涉及宏任务与微任务的知识,我们先来看看这样的一道题:
console.log('同步代码1'); setTimeout(function () { console.log("setTimeout"); }, 0); new Promise((resolve) => { console.log('同步代码2') resolve() }).then(() => { console.log('promise.then') }) console.log('同步代码3');
我们可能会问上面的输出是个啥,首先js是单线程,所以在js程序运行中只有一个执行栈,实现不了多线程,所以就需要任务均衡分配,通俗的讲,按任务急优先处理原则,js中分为同步任务和异步任务,异步任务又分为宏任务和微任务,同步任务先入栈,程序会先把执行栈中的所有同步任务执行完,再去判断是否有异步任务,而异步任务中微任务的优先级高于宏任务。如果当前执行栈为空,而微任务队列不为空,就先执行微任务,等把所有微任务执行完,最后才会考虑宏任务。而上面代码中Promise是属于微任务
,而setTimeout是宏任务
,所以上面的输出为:
// 同步代码1 // 同步代码2 // 同步代码3 // promise.then // setTimeout
传入回调函数参数使用:
this.$nextTick(()=>{ // ...操作DOM的代码 })
不传入回调函数参数使用:
// 方式一 this.$nextTick().then(()=>{ // ...操作DOM的代码 }) // 方式二 await this.$nextTick(); // 后写操作DOM的代码
Vue3版本就没有Vue2版本的那么多环境支持,nextTick封装成了一个Promise异步回调函数执行。
// Vue3.2.45 // core-main\core-main\packages\runtime-core\src export function nextTick<T = void>( this: T, fn?: (this: T) => void ): Promise<void> { const p = currentFlushPromise || resolvedPromise return fn ? p.then(this ? fn.bind(this) : fn) : p }
传入回调函数使用
import { nextTick } from 'vue' // 引入 setup () { nextTick(()=>{ // ...操作DOM的代码 })
不传入回调函数的使用
import { nextTick } from 'vue' // 引入 setup () { // 方式一 nextTick().then(()=>{ // ...操作DOM的代码 }) // 方式二 await nextTick(); // 后写操作DOM的代码 }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!