深入了解 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,只需要将其引入我们的项目中就可以达到效果

相关推荐
每天吃饭的羊4 分钟前
媒体查询
开发语言·前端·javascript
XiaoYu200228 分钟前
第8章 Three.js入门
前端·javascript·three.js
这个一个非常哈39 分钟前
element之,自定义form的label
前端·javascript·vue.js
阿东在coding1 小时前
Flutter 测试框架对比指南
前端
李瑞丰_liruifengv1 小时前
Claude Agent SDK 最简玩法:几行代码配合 Markdown 轻松搭建 Agent
javascript·人工智能·程序员
是李嘉图呀1 小时前
npm推送包失败需要Two-factor权限认证问题解决
前端
自己记录_理解更深刻1 小时前
本地完成「新建 GitHub 仓库 react-ts-demo → 关联本地 React+TS 项目 → 提交初始代码」的完整操作流程
前端
借个火er1 小时前
Chrome 插件开发实战:5 分钟上手 + 原理深度解析
前端
攀登的牵牛花1 小时前
前端向架构突围系列 - 架构方法(一):概述 4+1 视图模型
前端·设计模式·架构
Hashan1 小时前
Vue 3 中 v-for 动态组件 ref 收集失败问题排查与解决
前端·vue.js·前端框架