我正在尝试实现一个动画轮播,代码如下:
<template>
<div v-for="(slides, id)" v-if="id > middle_id - 2 || id < middle_id + 2">
<div :class="'slide'+id"><slide :key="id" :slide-data="slide" /></div>
</div>
</template>
幻灯片的数量是可变的,但只显示中间的 5 张。动画仅使用基于幻灯片编号的 css 动画。
如果我一次添加或删除一张幻灯片,则效果很好 - 现有的 dom 元素不会更改,只添加一张新幻灯片。但是,如果我在末尾添加一张幻灯片并同时从开头删除一张幻灯片,vue 似乎会重新渲染滑动窗口中的所有 dom 元素。
有没有办法保证在这个操作过程中,中间3张没有改变的slide不会在dom中更新?
在 Vue 3.2 及更高版本中,可以使用
v-memo
来完成
<div v-memo="[valueA, valueB]"> ... </div>
当组件重新渲染时,如果 valueA 和 valueB 保持不变,则该组件及其子组件的所有更新都将被跳过。 事实上,甚至 Virtual DOM VNode 创建也将被跳过,因为子组件的记忆副本-树可以重复使用。
我在使用Vue实现轮播文本时遇到了类似的问题,我找到了有效解决该问题的解决方案。
Vue 在其源代码中采用了某些启发式方法来确定是否在不同场景下回收 DOM 元素。具体来说,Vue 在以下情况下不会回收 DOM 元素
就您而言,当您一步添加和删除幻灯片时就会出现问题。当您添加一张幻灯片,然后在下一步中删除另一张幻灯片时,Vue 不会触发 DOM 元素的重新渲染。
Vue 异步更新 DOM,这意味着对数据的多次修改将被打包为一次,并且 DOM 只会更新一次。为了确保添加和删除幻灯片被视为单独的步骤,我发现利用
await Vue.nextTick()
(或 await this.$nextTick()
)是一种有效的方法。 await Vue.nextTick()
表示在 DOM 更新之前永远不要执行该行下面的代码。
要实现此解决方案,您可以按照下面提供的示例代码进行操作:
async function updateSlides() {
// Add a new slide to the array
this.arr.push({ ... })
// Wait for the DOM update, ensuring separate steps
await this.$nextTick()
// Remove the first slide from the array
this.arr.splice(0, 1)
}
通过遵循这种方法,您应该能够达到预期的结果并有效地解决问题。