vue $nextTick 实现原理

news2024/10/22 2:24:53

nextTick的实现

  • 一:nextTick介绍
  • 二:手写nextTick
  • 三:具体代码
  • 四:实现细节

一:nextTick介绍

nextTick 是 Vue.js 框架中的一个方法,它允许延迟执行一个函数,直到 DOM 更新完成。当你修改了数据并且希望基于更新后的 DOM 来执行某些操作时,nextTick就非常有用了。

在 Vue 中,当更改响应式数据时,Vue 会异步地执行 DOM 更新。这意味着,如果你立即尝试访问或操作刚刚被改变的数据所影响的 DOM 元素,那么可能还没有完成更新。nextTick 就是用来解决这个问题的,它会在下一个 DOM 更新周期后调用回调函数,确保能获取到最新的 DOM 状态。

下面用一个简单的例子来说明如何使用 nextTick:

// 假设此处有一个 Vue 实例和一个元素需要在数据变化后进行处理
new Vue({
  el: '#app',
  data: {
    message: 'Hello'
  },
  methods: {
    updateMessage() {
      this.message = 'Updated message';
      
      // 这里直接访问 DOM 可能不会得到更新后的状态
      // 因为 DOM 更新是异步的
      
      // 使用 nextTick 来确保 DOM 已经更新
      this.$nextTick(() => {
        // 在这个回调中,DOM 已经更新到了最新状态
        console.log(document.querySelector('#message').textContent); // 应该输出 "Updated message"
      });
    }
  }
});

// HTML 模板
<div id="app">
  <p id="message">{{ message }}</p>
  <button @click="updateMessage">Update Message</button>
</div>

在这个例子中,当点击按钮触发 updateMessage 方法时,message 数据会被更新。由于 DOM 更新是异步的,直接在数据更新之后访问 DOM 不一定会看到变化。但是通过 this.$nextTick,我们可以保证在 DOM 完成更新之后再执行回调函数内的代码。

需要注意的是,nextTick 并不只用于 Vue.js,类似的机制也存在于其他一些 JavaScript 库和框架中,比如 React 的 useEffect 钩子也可以用来实现类似的功能。不过在 Vue 中,nextTick 提供了一个更直接的方式来处理这种情况。

二:手写nextTick

想要实现nextTick,以下是我们需要关注的点

  1. DOM 更新是异步的: 浏览器在处理 JavaScript 时,通常会将 DOM 操作放入一个队列中,并且在当前任务完成后才会执行这些操作。这意味着如果修改了一个数据模型并立即尝试访问更新后的 DOM,可能看不到最新的更改,因为 DOM 更新还没有发生。
  2. Promise 和异步执行: 通过返回一个 Promise,这段代码可以等待直到 DOM 更新完成后再解决这个 Promise。这样,可以使用 .then() 或 await 来确保你的代码在 DOM 更新后执行。
  3. MutationObserver 的作用: MutationObserver 是一种可以用来监听 DOM 树变化的 API。它允许在特定节点或整个文档上设置观察者,当被观察的节点发生变化(如属性改变、子节点添加/删除等)时,MutationObserver 会触发回调函数。当使用 MutationObserver 并调用其 observe 方法时,这个观察者会被安排在下一个微任务队列中运行。这与 Vue 的 nextTick 类似,后者也是利用了微任务机制来确保在下一次 DOM 更新循环之后执行代码。

三:具体代码

function nextTick(fn) {
    return new Promise((resolve, reject) => {
      // DOM更新完成否?
      if (typeof MutationObserver !== 'undefined') {//考虑到可能部分浏览器不能兼容MutationObserver
        const observer = new MutationObserver(() => {
          let res = fn()
          if (res instanceof Promise) {
            res.then(resolve)
          } else {
            resolve()
          }
        })        
        observer.observe(document.getElementById('app'), { attributes: true, childList: true, subtree: true })
      }
    })
  }

四:实现细节

  • 创建 MutationObserver
    • new MutationObserver(callback) 创建一个新的观察者实例。
    • observer.observe(target, options) 开始观察指定的目标元素和选项。上述代码中,目标是 document.getElementById(‘app’),并且设置了 attributes: true, childList: true, subtree: true 以监听所有相关的变化。
  • 回调函数:
    • 当观察到任何变化时,回调函数会被调用。
    • 在回调函数中,执行传入的 fn 函数。
    • 如果 fn 返回的是一个 Promise,则等待该 Promise 解决后再解决外部的 Promise;否则直接解决外部的 Promise。

这里面试官可能会问nextTick是宏任务还是微任务,虽然MutationObserver观察者会被安排在下一个微任务队列中运行,但并不代表nextTick就是一个微任务,当回调函数中执行的函数是一个异步代码时,nextTick里面的promise状态需要等待内部回调中的异步函数返回的peomise状态变更完成后,才能变更,此时nextTick就是一个宏任务

总的来说,这个方式是利用了 MutationObserver 来捕捉 DOM 更新,从而提供了一种机制,可以在 DOM 更新完成后执行一些操作。这种方法并不依赖于 Vue.js 或其他框架,而是基于标准的 Web API,因此具有很好的兼容性和通用性,可以作为一个跨平台的解决方案,用于需要在 DOM 更新后执行某些逻辑的场景。

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

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

相关文章

pandas-使用技巧

pandas-使用技巧 简单技巧 仅个人笔记使用&#xff0c;感谢点赞关注 简单技巧 pd.to_dict()&#xff1a;Dataframe格式数据转字典数据pd.dropna()&#xff1a;去nan值& | ~&#xff1a;pd逻辑运算符pd.isnan()&#xff1a;判断是否为nan值pd.concat&#xff1a;多个pd拼接…

关于武汉芯景科技有限公司的限流开关芯片XJ6241开发指南(兼容LTC4411)

一、芯片引脚介绍 1.芯片引脚 二、系统结构图 三、功能描述 1.CTL引脚控制VIN和VOUT的通断 2.CTL引脚控制STAT引脚的状态 3.输出电压高于输入电压加上–VRTO的值&#xff0c;芯片处于关断状态

揭秘Map与Set的键值奥秘与集合魅力,解锁高效数据魔法

文章目录 前言➰一、关联式容器1.1 关联式容器的概述1.2 关联式容器的工作原理1.3 关联式容器的核心特性 ➰二、键值对2.1 键值对的基本概念2.2 键值对在C中的实现 ➰三、树形结构的关联式容器3.1 树形结构的特点3.2 使用场景 ➰四、set的使用与定义4.1 set的基本特性4.2 set的…

OpenCV高级图形用户界面(11)检查是否有键盘事件发生而不阻塞当前线程函数pollKey()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 轮询已按下的键。 函数 pollKey 无等待地轮询键盘事件。它返回已按下的键的代码或如果没有键自上次调用以来被按下则返回 -1。若要等待按键被按…

软件压力测试如何进行?深圳软件测试机构分享

软件压力测试是每个重要软件测试工作的一部分&#xff0c;是一种基本的软件质量保证行为。压力测试不是在常规条件下运行手动或自动测试&#xff0c;而是在计算机数量较少或系统资源匮乏的条件下运行测试。通常要进行软件压力测试的资源包括内部内存、CPU 可用性、磁盘空间和网…

算法day-1

数组&#xfeff; 数组是存放在连续内存空间上的相同类型数据的集合。数组的下标或者索引是从0开始的. 数组的优点 快速访问&#xff1a;通过索引可以在常数时间内&#xff08;O(1)&#xff09;访问数组中的任意元素。顺序存储&#xff1a;数组中的元素在内存中是连续的&…

Codeforces 979 Div2 A-D (D. QED‘s Favorite Permutation详解)

比较开心能做出D A 原题 A. A Gift From Orangutan 思路 找到最大值最小值差值乘n - 1 即可 代码 #include <bits/stdc.h> #define int long long#define F(i, a, b) for (int i (a); i < (b); i) #define dF(i, a, b) for (int i (a); i > (b); i--)using…

C#学习笔记(一)

C#学习笔记&#xff08;一&#xff09; 简介第一章 上位机开发环境之 VS 使用和.NET 平台基础一、安装软件二、创建项目三、第一个Hello world四、解决方案与项目五、Debug 和 Release 的区别六、代码的生产过程七、CLR的其它功能 简介 C# .NET工控上位机开发 在工控领域&…

Nuxt.js 应用中的 build:before 事件钩子详解

title: Nuxt.js 应用中的 build:before 事件钩子详解 date: 2024/10/20 updated: 2024/10/20 author: cmdragon excerpt: build:before 钩子在 Nuxt.js 中是一种有力的工具,使开发者能够在应用的构建流程开始之前进行自定义处理和配置。在处理动态需求和配置时,开发者可以…

深度解析RLS(Recursive Least Squares)算法

目录 一、引言二、RLS算法的基本思想三、RLS算法的数学推导四、RLS算法的特点五、RLS算法的应用场景六、RLS算法的局限性七、总结 一、引言 在自适应滤波领域&#xff0c;LMS&#xff08;Least Mean Squares&#xff09;算法因其计算简单、实现方便而广受欢迎。然而&#xff0…

C++ 哈希桶和封装unordered_map和unordered_set

目录 哈希桶的概念 哈希桶的结构 哈希桶的结点 哈希桶的类 Insert插入函数 Find查找函数 Erase删除函数 哈希的两种仿函数(int) 和(string) 哈希表的改造 ​编辑 迭代器 改造 unordered_map和unordered_set的封装 前言 上一篇文章讲的哈希表&#xff0c;属于闭散…

解决k8s集群中安装ks3.4.1开启日志失败问题

问题 安装kubesphere v3.4.1时&#xff0c;开启了日志功能&#xff0c;部署时有三个pod报错了 Failed to pull image “busybox:latest”: rpc error: code Unknown desc failed to pull and unpack image “docker.io/library/busybox:latest”: failed to copy: httpRead…

【D3.js in Action 3 精译_034】4.1 D3 中的坐标轴的创建(中篇):定义横纵坐标轴的比例尺

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

京存助力北京某电力研究所数据采集

北京某电力研究所已建成了一套以光纤为主&#xff0c;卫星、载波、微波等多种通信方式共存&#xff0c;分层级的电力专用的网络通信架构体系。随着用电、配电对网络的要求提高&#xff0c;以及终端通信入网的迅速发展&#xff0c;迫切地需要高效的通信管理系统来应对大规模、复…

STM32传感器模块编程实践(七) MLX90614红外测温模块简介及驱动源码

文章目录 一.概要二.MLX90614主要技术指标三.模块参考原理图四.模块接线说明五.模块工作原理介绍六.模块通讯协议介绍七.STM32单片机与MLX90614模块实现体温测量实验1.硬件准备2.软件工程3.软件主要代码4.实验效果 八.小结 一.概要 一般来说&#xff0c;测温方式可分为接触式和…

大模型常见算子定义

本文将汇总大模型常用的算子定义&#xff0c;方便快速根据定义公式评估其计算量。 LayerNorm 这是在BERT、GPT等模型中广泛使用的LayerNorm&#xff1a; RMSNorm RMSNorm(root mean square)发现LayerNorm的中心偏移没什么用(减去均值等操作)。将其去掉之后&#xff0c;效果几乎…

51系列--人体身高体重BMI指数检测健康秤

本文主要介绍基于51单片机实现的人体身高体重BMI指数检测健康秤称设计&#xff08;程序、电路图、PCB以及文档说明书见文末链接&#xff09; 一、简介 本系统由STC89C52单片机、LCD1602液晶显示、按键、超声波测距、HX711称重传感器模块&#xff08;0-1000KG&#xff09;以及…

O(1)调度算法与CFS

目录 引言 linux内核的O&#xff08;1&#xff09;进程调度算法介绍 主要特点 工作原理 优点 缺点 运行队列 活动队列 过期队列 active指针和expired指针 O(1)调度器&#xff0c;两个队列的机制 两个队列的机制如下&#xff1a; 这个算法后期被CFS替代 CFS 工作原…

进阶篇-Redis集群算法详细介绍

目录 一 、集群是什么1.1 主从复制与集群的架构区别 二、Redis集群的作用三、集群算法3.1.分片-槽位slot3.2 分片是什么3.3如何找到找到给定的key值分片3.4分片的优势 四、槽位映射的三中国解决方案4.1 哈希取余分区算法4.2 哈希一致性算法4.2.1 背景以及概念4.2.2 算法的步骤4…

【Python加密与解密】深入了解Python中的数据加密技术!

Python加密与解密&#xff1a;深入了解Python中的数据加密技术 在现代信息时代&#xff0c;数据加密成为保障网络和通信安全的重要手段之一。无论是在保护个人隐私还是在保证企业数据的安全性方面&#xff0c;加密技术都发挥着关键作用。Python 作为一种流行的编程语言&#x…