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

相关推荐
gnip13 小时前
企业级配置式表单组件封装
前端·javascript·vue.js
一只叫煤球的猫14 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
excel15 小时前
Three.js 材质(Material)详解 —— 区别、原理、场景与示例
前端
掘金安东尼16 小时前
抛弃自定义模态框:原生Dialog的实力
前端·javascript·github
hj5914_前端新手19 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
薛定谔的算法19 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku20 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode20 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu20 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu20 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript