前端开发:$nextTick()的使用及原理

news2024/12/23 21:03:38

目录

前言

$nextTick()的概念

$nextTick()的用法和原理

1、$nextTick()用法

2、$nextTick()原理

$nextTick()的具体使用示例

拓展:面试中考察$nextTick()的底层原理

最后


前言

在前端开发中,涉及到JS原生的使用原理是非常重要的知识点,尤其是在实际工作过程中会遇到各种复杂的业务需求场景,以及具体开发中可能会遇到一些涉及基于JS原理的使用,这都要求开发者能够很好的了解和掌握JS原生的常用原理。那么本篇博文就来分享一下关于$nextTick()的使用及原理,该内容不仅在日常前端开发中是比较重要核心的知识点,而且在前端求职面试时候面试官必考的知识点,总结记录一下,方便后期查阅使用。

$nextTick()的概念

在前端领域,$nextTick()其实就是一个延迟回调,在第一时间获取更新后的DOM;也就是说,Vue在更新DOM时是异步执行的,即当数据发生变化时,Vue将开启一个异步更新的队列,当视图的数据变化完成之后,再统一进行更新的处理。

众所周知,Vue是异步执行DOM更新,通过数据劫持结合发布者--订阅者模式的数据双向绑定来观察数据变化,如果数据发生变化就会开启一个队列,且watcher会被触发多次,只会推送到队列一次,但在下次事件循环的时候会清空队列并进行DOM的更新,在Vue内部会尝试对异步队列使用原生的promise.then和MutationObserver,若当前执行环境不支持该操作会采用setTime(()=> {} , 0)代替。若某一个DOM不会马上更新,而是会在下一个事件循环的时候才会更新,但是这个时候需要该DOM进行某些操作,此时就可以通过使用$nextTick()来实现上述需求操作。

$nextTick()的用法和原理

1、$nextTick()用法

在$nextTick()使用时候,尤其是在生命周期中使用时必须要在mounted中进行操作,因为在此时才能获取到el。具体的使用语法如下所示:

this.$nextTick(() => {

//业务逻辑处理。nextTick()中默认传一个箭头函数,开发者需要在箭头函数中进行实际的业务逻辑处理

})

$nextTick()的主要应用场景及原因:

(1)当Vue生命周期的created()钩子函数进行的DOM操作,一定要放在Vue.nextTick()的回调函数中,因为created钩子函数阶段DOM 并没有进行任何渲染, 而此时对DOM进行操作是无用的, 所以一定要将DOM操作的JS代码放进Vue.nextTick()回调函数中, 与它之对应的就是mounted()钩子函数, 因为mounted()钩子函数执行时所有的DOM 挂载和渲染都已完成, 在mounted()钩子函数中进行任何操作都不会有问题。

(2)当数据变化后要执行某个回调函数,但该操作需要使用根据数据改变而改变的DOM结构时, 该操作就需要在Vue.nextTick () 回调函数中使用,也就是获取数据更新之后的DOM的时候使用。

(3)在实际开发中,需要获取元素宽度的时候,该操作就需要在Vue.nextTick () 回调函数中使用。

2、$nextTick()原理

在Vue中$nextTick()的实现主要是基于微任务队列,它主要通过原生的Promise.then 或MutationObserver来实现,但是需要注意的是$nextTick()更多地会选择Promise.then进行触发,因为在 iOS(>= 9.3.3)版本之后,MutationObserver在触发几次之后会失效。

$nextTick()的实现在Vue中采用多种方式,具体使用的方式实现取决于实际开发环境,大多数情况是用 Promise.then来实现,而且$nextTick()并不是一个个单独执行的。首先,会把代码中所有的$nextTick()收集在一起,存放到数组callbacks(相当于队列)中,然后通过对应环境下的微任务方法去执行flushCallbacks方法,也就是遍历calllhacks数组中存的每一个$nextTick()方法,然后把callbacks数组清空处理。

在DOM更新的时候,后面将获取不到更新后的最新的变量,如果没有$nextTick(),每次改变数据都会触发视图去更新,极其浪费资源。因此有了该机制,只需统一更新一次即可。

异步说明:Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新操作。

(1)其实Vue 是异步执行dom更新的,当观察到数据变化,Vue 就会开启一个队列,把在同一事件循环中观察到数据变化的watcher推送到这个队列,若该watcher被触发多次,但是只会被推送到队列一次,该缓冲行为可以有效的去掉重复数据造成的不必要的计算和dom操作,就可以提高渲染效率;

(2) 若要获取更新后的dom元素,可使用Vue 内置的$nextTick()方法,它的参数是一个函数,作用类似setTimeout,执行异步操作。

事件循环说明:当Vue 在修改数据之后,视图不会立马更新,而是等同一事件循环中的所有数据变化完成之后再统一进行视图更新。

(1)Vue 中的nextTick()主要用于处理数据动态变化之后,当DOM还未及时更新的问题,用nextTick()可以获取数据更新后最新dom的变化;

(2)在created()钩子函数执行的时候,DOM并未进行任何渲染,而此时进行DOM操作并无作用,但在created()里使用this.$nextTick()可以等待DOM生成以后再来获取DOM对象。

(3)为了使数据变化之后等待Vue完成更新DOM,可在数据变化之后立即使用vue.nextTick(callback),可以让回调函数在DOM更新完成后就会调用;在下次DOM更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的DOM。

注意: mounted()钩子函数不会承诺所有子组件都一起被挂载,若希望等到整个视图都渲染完毕,可以用 vm.$nextTick()替换掉mounted()。

$nextTick()的具体使用示例

示例一:

在实际开发中关于$nextTick()的具体使用有很多情况,这里只来举一个关于在DOM更新的时候,后面将获取不到更新后的最新的变量的示例,具体如下所示:

<template>
<div class="hom">
<div ref="button">{{ message }}</div>
<button @click="change()">change</button>
</div>
</template>
<script>
export default {
data() {
return {
message: "111",
}
},
methods: {
change() {
this.message = "222"
console.log(this.$refs.button.innerText)
}
}
}
</script>

这时候点击按钮触发方法,虽然改变了div上的message值,但由于异步的原因,通过ref无法获取div上的值,因为这时候DOM并未更新,所以输出的结果是“111”。针对这种情况,对change()方法进行修改,在方法中使用$nextTick(),从而获取更新后的DOM值,具体修改后的change()方法代码如下所示:

change() {
this.message = "222"
this.$nextTick(()=>{
console.log(this.$refs.button.innerText)
})
}
//输出结果为“222”,也就是获取到最新的值

示例二

关于nextTick()方法的具体使用,如下所示:

1、首先把nextTick()方法定义在 src/util/next-titck.js文件中

export function nextTick (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)
}
})
if (!pending) {
pending = true
timerFunc()
}
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}

上面就是,当调用cb回调函数的时候,使用try和catch进行包裹,防止出错崩溃。

示例三:

在Vue中this.$nestTick的作用就是产生一个回调函数,然后在新一轮dom更新后执行该回调函数。比如当某操作需要等待数据被修改更新之后再操作,就可以将操作放在this.$nextTick的回调函数中执行,也就是并不是vue数据一旦发生修改就会立即更新。在一个按钮点击事件中修改vue中的数据message,用dom来获取修改之后的值, 也就是在执行一个dom更新周期后,调用了this.$nextTick的回调函数,具体的使用如下所示:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="hom">
<input type="button" @click="change()" value="点击" id="i" >
<div id="msg">{{message}}</div>
</div>
    <script src="js/vue.js"></script>
    <script>
const app = new Vue({
            el:"#app",
            data:{
                message:"111"
            },
            methods:{
                change(){
                    this.message = "222"; 
                    console.log("当前值: "+document.getElementById('msg').innerText);
                }
            }
        })
</script>
</body>
</html>

实际需要输出的是当前文本的值:222 ,但输出的值其实是:111,原因就是在获取值的时候,还没有更新message。可以把获取id=msg的值的相关代码放在this.$nextTick()回调函数中,具体修改后的代码如下所示:

change(){
    this.message = "222";
    this.$nextTick(function(){
        console.log("当前值: "+document.getElementById('msg').innerText);
    });
}
//输出结果为:222,即获取到最新修改的值

拓展:面试中考察$nextTick()的底层原理

在前端求职面试中,$nextTick()的底层原理是面试官必考知识点。一般面试官会问$nextTick()的底层原理是什么?可能还会给一个实际场景:前端页面轮播图初始化的时候拿不到DOM怎么办?解决方式:使用watch结合$nextTick()的组合使用来解决。

分析:其实有两个$nextTick():第一个是Vue内部的$nextTick()函数,第二个则是实际调用的nextTick/$nextTick()函数,而面试官问的$nextTick()的底层原理并不是问怎么调用$nextTick()函数的。

搞懂$nextTick()的底层原理前提:DOM的更新和渲染是两回事;DOM的更新也是异步的(当更新data里的一个数据的时候,若赋两遍值,第二遍赋的值会覆盖第一遍的值,真是这样,DOM更新也是异步的,而且DOM内部也是用$nextTick()来实现的)。

$nextTick()的底层原理:在DOM更新异步执行的时候,其内部的$nextTick()要进入微队列,且是先进入,我们写的$nextTick()也是要进入微队列 , 但是晚于DOM更新的$nextTick(),这样内部写的回调就可在第一时间获取到DOM更新的数据了。

在事件队列里中执行的详情,如下图所示:

小结:DOM更新的内部也是使用$nextTick(),是异步的先进入事件队列,且此时还没有渲染DOM;$nextTick()后进入事件队列,等待第一步的$nextTick()执行完之后再执行,最后再进行DOM渲染。

注意:$nextTick()内部会优先考虑使用Promise微任务,若浏览器不支持,则会使用setImmediate、setTImeout等宏任务。

最后

通过本文关于前端开发中$nextTick()的使用及原理的详细介绍,$nextTick()的使用不管是在实际的前端开发工作中还是在前端求职面试中都是非常关键的知识点,所以作为前端开发者来说必须要掌握它相关的内容,尤其是从事前端开发不久的开发者来说尤为重要,是一篇值得阅读的文章,重要性就不在赘述。欢迎关注,一起交流,共同进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1718747.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot详解:深入了解与实践

文章目录 1. Spring Boot简介1.1 什么是Spring Boot&#xff1f;1.2 Spring Boot的历史背景1.3 Spring Boot的核心特点 2. Spring Boot的核心概念2.1 自动配置2.1.1 自动配置原理2.1.2 自定义配置 2.2 Spring Boot Starter2.3 Spring Boot CLI 3. Spring Boot的主要功能模块3.1…

Microsoft Dynamics 365 Business Central 讲解VAT RATE CHANGE TOOL(增值税税率更改工具)

学习目标&#xff1a; 如果使用VAT RATE CHANGE TOOL&#xff08;增值税税率更改工具&#xff09; 过程演示&#xff1a; 1.创建新的VAT产品过账组 2.创建新的总账科目以过账采购、销售和逆向征收增值税。 3.给新的VAT产品过账设置过账设置 4.创建一个新的一般产品过账组 5…

百度地图1

地图的基本操作 百度地图3.0文档 百度地图3.0实例中心 设置地图 centerAndZoom(center: Point, zoom: Number)设初始化地图,center类型为Point时&#xff0c;zoom必须赋值&#xff0c;范围3-19级&#xff0c; // 百度地图API功能var map new BMap.Map("map"); //…

element-plus关于表单数据自定义参数校验

element-plus关于表单数据自定义参数校验 核心点&#xff1a; 代码&#xff1a; <el-form-item :prop"tableData[ scope.$index ].score":rules"[{ required: true, message: 得分不能为空, trigger: blur },{ validator: (rule: any, value: any, ca…

2024最新群智能优化算法:大甘蔗鼠算法(Greater Cane Rat Algorithm,GCRA)求解23个函数,提供MATLAB代码

一、大甘蔗鼠算法 大甘蔗鼠算法&#xff08;Greater Cane Rat Algorithm&#xff0c;GCRA&#xff09;由Jeffrey O. Agushaka等人于2024年提出&#xff0c;该算法模拟大甘蔗鼠的智能觅食行为。 参考文献 [1]Agushaka J O, Ezugwu A E, Saha A K, et al. Greater Cane Rat Alg…

Whisper-AT:抗噪语音识别模型(Whisper)实现通用音频事件标记(Audio Tagger)

本文介绍一个统一音频标记&#xff08;Audio Tagger&#xff09;和语音识别&#xff08;ASR&#xff09;的模型&#xff1a;Whisper-AT&#xff0c;通过冻结Whisper的主干&#xff0c;并在其之上训练一个轻量级的音频标记模型。Whisper-AT在额外计算成本不到1%的情况下&#xf…

MySQL 命令总结篇-思维导图

一些常用命令以思维导图形式总结在这里了&#xff0c;掌握这些进行MySQL基本操作绝对没问题&#xff0c;加油&#xff01;友友们可以根据这些思维导图进行知识总结。 目录 一、快速上手 二、SQL 语句分类&#xff08;DDL、DML、DQL、DCL&#xff09; 三、数据类型 四、约束…

图书管理系统——Java实现

文章目录 Java实现图书管理系统问题分析框架搭建业务实现项目测试代码演示BookioperationUserMain&#xff08;默认包&#xff09; Java实现图书管理系统 学习了前六篇的SE语法&#xff0c;我们现在要用它们实现一个简单的图书管理系统项目&#xff0c;深入了解各个知识点的应…

阿里云CDN流量被盗刷或CC攻击会怎么样?

最近&#xff0c;一位使用了阿里云CDN的站长向主机吧反应&#xff0c;其域名使用的阿里云CDN不知道是因为被盗刷还是被CC攻击&#xff0c;导致不仅原本帐号上的3T流量包用完了&#xff0c;连帐户也欠了几百元的流量费。 而产生这么多流量的只是晚上睡一觉起来&#xff0c;手机…

SpringCloud如何实现SSO单点登录?

目录 一、SpringCloud框架介绍 二、什么是SSO单点登录 三、单点登录的必要性 四、SpringCloud如何实现SSO单点登录 一、SpringCloud框架介绍 Spring Cloud是一个基于Spring Boot的微服务架构开发工具集&#xff0c;它整合了多种微服务解决方案&#xff0c;如服务发现、配置…

Element ui 快速入门(基础知识点)

element ui官网 前言&#xff1a; 在当今时代&#xff0c;我们在编写计算机程序时&#xff0c;不仅仅是写几个增删改查的简单功能&#xff0c;为了满足广大用户对页面美观的需求&#xff0c;为了让程序员们写一些功能更简便&#xff0c;提高团队协作效率&#xff0c;所以eleme…

西藏大学计科改考11408!西藏大学计算机考研考情分析!

西藏大学&#xff08;Tibet University&#xff09;&#xff0c;简称藏大&#xff0c;是西藏自治区所属的综合性大学&#xff0c;是列入教育部直属高校序列的教育部与西藏自治区人民政府合建高校&#xff0c;国家“211工程”重点建设大学&#xff0c;国家“双一流”世界一流学科…

《HelloGitHub》第 98 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

【康耐视国产案例】智能AI相机机器视觉精准快速实现包裹标签的智能粘贴

康耐视推出的3D-A1000是专业的、匹配物流行业各类分拣机及包裹检测应用的全功能视觉检测系统&#xff0c;其能够准确检测分拣机上是否有包裹、包裹是否超出边界、空车检测、是否有遗留物品等。由于搭载了专利的三维结构光技术&#xff0c;产品具有更强大的创新性以满足持续更新…

dubbo复习:(18)服务端Filter

用来在服务响应返回到客户端之前进行额外处理。 一、定义Filter package cn.edu.tju.config;import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invocation; import org.apache.du…

AI新纪元:OpenAI GPT-4o模型发布,开启智能交互革命!

目录 前言一、 总体概述二、能力探索1、文字生成图片2、3D 物体合成3、音频提炼总结4、视频讲座总结 三、 模型评估1、文本评估2、音频ASR评估3、音频翻译性能4、M3Exam零样本结果5、视觉理解评估 四、 OpenAI API使用1、文本聊天2、图像解析3、上传 Base 64 编码图像4、多幅图…

【网关】工业智能网关-02

一 公司简介 保定飞凌嵌入式技术有限公司始于2006年&#xff0c;是一家专注嵌入式核心控制系统研发、设计和生产的高新技术企业&#xff0c;是国内最早专业从事嵌入式技术的企业之一。 经过十几年的发展与积累&#xff0c;公司拥有业内一流的软硬件研发团队&#xff0c;在北京…

深入理解 Go 语言中的字符串不可变性与底层实现

文章目录 前言1 字符串类型的数据结构组成2 为什么要这么设计数据结构&#xff1f;3 为什么说字符串类型不可修改&#xff1f;4 如何实现字符串的修改&#xff1f;5 为什么字符串修改的字面量用单引号&#xff1f;6 如何判断字符串的修改新建了一个字符串&#xff1f;7 字符串的…

网桥、路由器和网关有什么区别

在计算机网络领域&#xff0c;网桥、路由器和网关都是常见的网络设备&#xff0c;它们在网络通信中扮演着不同的角色。虽然它们都有连接不同网络的功能&#xff0c;但在实际应用中却具有各自独特的作用和特点。 1.网桥&#xff08;Bridge&#xff09; 定义&#xff1a;网桥是…

Mac逆向Electron应用

工具库 解压asar文件 第一步 找到应用文件夹位置 打开活动监视器&#xff1a; 搜索相关应用 用命令行打开刚才复制的路径即可 open Applications/XXX.app/Contents/Resources/app第二步 解压打包文件 解压asar文件