使用nextTick
nextTick是Vue框架提供的一个用于延迟回调函数至DOM更新后的方法,常用于Vue中异步更新组件后获取DOM状态等。
下面是一个点击按钮异步新增列表项,并滚动列表至最后一个元素的例子:
<template>
<button @click="handleAddItem">Add item</button>
<div class="container">
<ul>
<li v-for="(item, index) in list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, nextTick } from 'vue';
const list = ref([1,2,3]);
// 注意2:此处方法应为异步
const handleAddItem = async() => {
list.value.push(list.value.length + 1);
// 使用 setTimeout 模拟异步进程
await setTimeout(() => {
nextTick(() => {
const lastItem = document.querySelector('li:last-child');
lastItem.scrollIntoView({behavior:'smooth'});
});
}, 200)
};
</script>
<style>
/* 注意1:容器需要限制高度并设置overflow行为 */
.container {
height: 100px;
overflow-y: scroll;
}
</style>
有两个需要注意的地方:
- 滚动的列表容器应当限制其高度,并设置
overflow
行为为scroll
nextTick
使用await
异步调用。
模拟一个nextTick功能
使用DOM4新增的MutationObserver接口,它可以监视指定DOM节点发生的变化。
CustomNetTick.js
export default function myNextTick(targetNode, callbackFunc) {
// config 指定监视的属性、子节点等
const config = { attributes: true, childList: true, subtree: true };
const callback = function (mutationList, observer) {
let text = '';
console.log(mutationList);
for (let mutation of mutationList) {
if (mutation.type === 'childList') {
text = 'A child node has been added or removed.';
} else if (mutation.type === 'attributes') {
text = 'The ' + mutation.attributeName + ' attribute was modified.';
}
}
callbackFunc(text);
};
const observer = new MutationObserver(callback);
// 开始监视
observer.observe(targetNode, config);
}
在原来的页面中调用该方法
const handleAddItem = async () => {
list.value.push(list.value.length + 1);
// 使用 setTimeout 模拟异步进程
await setTimeout(() => {
//nextTick(() => {
// const lastItem = document.querySelector('li:last-child');
// lastItem.scrollIntoView({ behavior: 'smooth' });
//});
// ——————————————————————————————————————————
// 此处监视列表项,能体现子元素变化
const target = document.querySelector('ul');
// 传入要监视的节点 target
myNextTick(target, (res) => {
console.log(res);
});
}, 200);
};
结果如下:
参考:
10 分钟了解 nextTick ,并实现简易版的 nextTick