都快2023年,你还不会this.$nextTick吗,Vue2都出快10年了,Vue3也已经出了两年多了,没错!说出来就丢脸,我现在才会this.nextTick(实话实说),好的咱先百度一下,哒哒哒....网速飞快地跳到了Vue.js官网文档,突然发现文档中有一言?:
nextTick:在下一次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。它有两个参数:第一个参数是
回调函数
,不传时提供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操作代码
。那么问题又来了,nextTick究竟做了什么?下面我们一起从源码层面来分别分析Vue2和Vue3版本的nextTick原理是啥。
Vue2版本的nextTick
由于Vue暴露给开发者的是nextTick这个方法,在这个方法中主要做了三件事,回调函数的添加、延迟执行回调函数、判断当前的nextTick是否传入回调函数。不传的话,是一个Promise,this.$nextTick.then(()=>{}),按Promise处理。
- 回调函数添加入callbacks数组,因为可能有多个nextTick函数在当前作用域中。
- 判断当前nextTick是否已经标记为pending=true,也就是正在执行,如果不是就执行timerFunc(异步执行函数 用于异步延迟调用 flushCallbacks 函数)。timerFunc的执行,判断当前环境是否支持promise、MutationObserver、setImmediate、setTimeout,优先级高低从前到后,分四种情况:
- 优先使用Promise,如果当前环境支持promise,nextTick默认优先使用promise去执行延迟回调函数,timerFunc执行的是Promise,promise是es6下的语法,如果当前环境只支持es6以语法下的,只能考虑后面支持情况了。
-
支持MutationObserver,HTML5的api,中文意思是:修改的监听,MutationObserver
用来监听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
使用Vue2的nextTick
-
传入回调函数参数使用:
this.$nextTick(()=>{ // ...操作DOM的代码 })
-
不传入回调函数参数使用:
// 方式一 this.$nextTick().then(()=>{ // ...操作DOM的代码 }) // 方式二 await this.$nextTick(); // 后写操作DOM的代码
Vue3版本的nextTick
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 }
使用Vue3的nextTick
-
传入回调函数使用
import { nextTick } from 'vue' // 引入 setup () { nextTick(()=>{ // ...操作DOM的代码 })
-
不传入回调函数的使用
import { nextTick } from 'vue' // 引入 setup () { // 方式一 nextTick().then(()=>{ // ...操作DOM的代码 }) // 方式二 await nextTick(); // 后写操作DOM的代码 }
总结
- nextTick可以通俗的当作一个Promise,所以nextTick属于微任务。
- nextTick在页面更新数据后,DOM更新,可以通俗理解为,nextTick就是用来支持操作DOM的代码及时更新渲染页面。也就是在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
- 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。
以上是带你深入了解下this.$nextTick!的详细内容。更多信息请关注PHP中文网其他相关文章!

Vue.js和React各有优势:Vue.js适用于小型应用和快速开发,React适合大型应用和复杂状态管理。1.Vue.js通过响应式系统实现自动更新,适用于小型应用。2.React使用虚拟DOM和diff算法,适合大型和复杂应用。选择框架时需考虑项目需求和团队技术栈。

Vue.js和React各有优势,选择应基于项目需求和团队技术栈。1.Vue.js社区友好,提供丰富学习资源,生态系统包括VueRouter等官方工具,支持由官方团队和社区提供。2.React社区偏向企业应用,生态系统强大,支持由Facebook及其社区提供,更新频繁。

Netflix使用React来提升用户体验。1)React的组件化特性帮助Netflix将复杂UI拆分成可管理模块。2)虚拟DOM优化了UI更新,提高了性能。3)结合Redux和GraphQL,Netflix高效管理应用状态和数据流动。

Vue.js是前端框架,后端框架用于处理服务器端逻辑。1)Vue.js专注于构建用户界面,通过组件化和响应式数据绑定简化开发。2)后端框架如Express、Django处理HTTP请求、数据库操作和业务逻辑,运行在服务器上。

Vue.js与前端技术栈紧密集成,提升开发效率和用户体验。1)构建工具:与Webpack、Rollup集成,实现模块化开发。2)状态管理:与Vuex集成,管理复杂应用状态。3)路由:与VueRouter集成,实现单页面应用路由。4)CSS预处理器:支持Sass、Less,提升样式开发效率。

Netflix选择React来构建其用户界面,因为React的组件化设计和虚拟DOM机制能够高效处理复杂界面和频繁更新。1)组件化设计让Netflix将界面分解成可管理的小组件,提高了开发效率和代码可维护性。2)虚拟DOM机制通过最小化DOM操作,确保了Netflix用户界面的流畅性和高性能。

Vue.js被开发者喜爱因为它易于上手且功能强大。1)其响应式数据绑定系统自动更新视图。2)组件系统提高了代码的可重用性和可维护性。3)计算属性和侦听器增强了代码的可读性和性能。4)使用VueDevtools和检查控制台错误是常见的调试技巧。5)性能优化包括使用key属性、计算属性和keep-alive组件。6)最佳实践包括清晰的组件命名、使用单文件组件和合理使用生命周期钩子。

Vue.js是一个渐进式的JavaScript框架,适用于构建高效、可维护的前端应用。其关键特性包括:1.响应式数据绑定,2.组件化开发,3.虚拟DOM。通过这些特性,Vue.js简化了开发过程,提高了应用性能和可维护性,使其在现代Web开发中备受欢迎。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

记事本++7.3.1
好用且免费的代码编辑器