深入了解 Vue.js 中的 nextTick:实现原理

今天我们来聊一聊vue中的nextTick,这是vue.js中的一个异步API,nextTick 的作用是将回调函数延迟到下次 DOM 更新周期之后执行。我们知道,在vue.js中数据是响应式的,当数据发生变化时,对应的DOM也会随着更新,但是DOM的更新并不是同步的,而是异步执行的,因此,在一些情况下,我们需要在DOM更新之后执行一些代码的话,就需要借助nextTick这个方法。

nextTick的功能与效果

话不多说,我们直接上示例,我们来看下面的这一段代码:为了不过于冗长,css省略

vue 复制代码
<template>
  <div>
    <button @click="addList">更新列表</button>
    <ul>
      <li v-for="item in list">{{ item }}</li>
    </ul>
  </div>
</template>

<script setup>
import { nextTick, ref } from 'vue'
const list = ref([])
list.value = [1,2,3,4,5,6,7,8,9,10]
const addList = () => {
  // 一次添加10个元素
  list.value.push(11,12,13,14,15,16,17,18,19,20)
  // 获取指定的元素,要求页面滚动到这个位置
  let lastDom = document.querySelector('li:last-child')
  lastDom.scrollIntoView()
}
</script>

运行之后我们会发现,虽然页面确实是滚动了,但是没有到达我们预期的位置,而是滚动到11就不动了,这是为什么呢?因为DOM的更新是异步的,而获取指定元素和滚动的执行代码是同步的,我们这里想要获取最后一个li,但实际上,DOM还没有更新完成,获取指定元素的代码就开始执行了,所以获取的并不是最后一个元素,自然也就没有达到我们想要的效果。

想要达到我们需要的效果,我们只需要把获取指定元素的代码和滚动的代码放进nextTick的回调中就好了

vue 复制代码
<script setup>
import { nextTick, ref } from 'vue'
const list = ref([])
list.value = [1,2,3,4,5,6,7,8,9,10]
const addList = () => {
  // 一次添加10个元素
  list.value.push(11,12,13,14,15,16,17,18,19,20)
  nextTick(() => {
    // 获取指定的元素,要求页面滚动到这个位置
    let lastDom = document.querySelector('li:last-child')
    lastDom.scrollIntoView()
  })
}
</script>

这样就可以达到我们想要的效果

手写一个简单的nextTick

那么怎么实现nextTick的效果呢,其实我们也可以手写一个简单的nextTick,帮助我们理解nextTick

nextTick接受一个回调函数作为形参,当页面上的DOM更新完成之后,执行回调中的代码

js 复制代码
// 创建一个简单的nextTick
function simpleNextTick(fn) { // 接受一个回调函数作为形参
    let dom = document.documentElement; // 获取文档对象
    let observer = new MutationObserver(() => { // 创建一个观察器 MutationObserver是一个内置的 JavaScript API,可以在 DOM 树中的节点发生变化时触发回调函数
        fn(); // 观察到变化后执行回调函数
    });
    observer.observe(dom, {
        attributes: true,
        childList: true,
        subtree: true
    }); // observe 是MutationObserver 的实例方法,用于观察文档对象的属性、子节点、后代节点变化
}

这样就完成了一个简单的nextTick,只需要将其引入我们的项目中就可以达到效果

相关推荐
橙序员小站1 小时前
Agent Skill 是什么?一文讲透 Agent Skill 的设计与实现
前端·后端
炫饭第一名4 小时前
速通Canvas指北🦮——基础入门篇
前端·javascript·程序员
王晓枫4 小时前
flutter接入三方库运行报错:Error running pod install
前端·flutter
符方昊4 小时前
React 19 对比 React 16 新特性解析
前端·react.js
ssshooter4 小时前
又被 Safari 差异坑了:textContent 拿到的值居然没换行?
前端
曲折4 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
Forever7_4 小时前
Electron 淘汰!新的桌面端框架 更强大、更轻量化
前端·vue.js
Angelial5 小时前
Vue3 嵌套路由 KeepAlive:动态缓存与反向配置方案
前端·vue.js
over6975 小时前
从 LLM 到全栈 Agent:MCP 协议 × RAG 技术如何重构 AI 的“做事能力”
面试·llm·mcp
jiayu5 小时前
Angular学习笔记24:Angular 响应式表单 FormArray 与 FormGroup 相互嵌套
前端