今天我们来聊一聊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,只需要将其引入我们的项目中就可以达到效果