列表数据的过渡效果

Vue 的实际项目中,有很多采用列表数据布局的页面,可以通过 v-for 指令来渲染一个列表页面,同时也可以结合 transition 组件来实现在列表渲染时的过渡效果。下面先来看一个简单的例子,如示例代码 5-7-1 所示。

示例代码 5-7-1 列表数据渲染
<div id="app">
    <div v-for="(item,index) in list" :key="item.id">{{item.id}}</div>
    <button @click="clickCallback">增加</button>
</div>
let count = 0;
Vue.createApp({
    data() {
        return {list: []}
    },
    methods:{
        clickCallback(){
            this.list.push({
                id: count++
            })
        }
    }
}).mount("#app")

在上面的代码中实现了简单的列表数据渲染。单击 “增加” 按钮会不断地向列表中添加数据。当然,在添加的过程中没有任何过渡或者动画效果。需要注意一下,使用 v-for 循环时,需要使用 key 属性来设置一个唯一的键值。

接下来,给增加的元素添加一个 “渐现” 的过渡效果,可以采用 transition-group 组件实现。这个组件的用法和 transition 组件类似,可以设置 name 属性为 listFade 来标识使用哪种过渡动画。接下来修改上面的部分代码,并添加相关的 CSS,如示例代码 5-7-2 所示。

.listFade-enter-from,.listFade-leave-to {
    opacity: 0;
}
.listFade-enter-to {
    opacity: 1;
}
.listFade-enter-active,.listFade-leave-active {
    transition: opacity 1s;
}
...
<transition-group name="listFade">
    <div v-for="(item,index) in list" :key="item.id">{{item.id}}</div>
</transition-group>

再次单击 “增加” 按钮,便可以体验到元素会有一个 “渐现” 的效果。在默认情况下,transition-group 组件在页面 DOM 中会以一个 <span> 标签的方式来包裹循环的数据,也可以设置一个 tag 属性来规定以哪种标签显示。代码如下:

<transition name="listFade" tag="div">...</transition>

使用了 transition-group 组件之后更形象一些,可以理解成 transition-group 组件给包裹的列表的每一个元素都添加了 transition 组件,当元素被添加到页面 DOM 中时,便会套用过渡动画效果。代码如下:

<transition-group name="listFade">
...
<transition>
<div>1</div>
</transition>
<transition>
<div>2</div>
</transition>
<transition>
<div>3</div>
</transition>
...
</transition-group>

同理,有了 “渐现” 效果,也可以添加 “渐隐” 效果,直接操作 list 这个数组即可,如示例代码 5-7-3 所示。

示例代码 5-7-3 列表数据渐隐

<div id="app">
    <button @click="add">增加</button>
    <button @click="remove">减少</button>
    <transition-group name="listFade">
        <div v-for="(item,index) in list" :key="item.id">{{item.id}}</div>
    </transition-group>
</div>
let count = 1;
Vue.createApp({
    data() {
        return {list: []}
    },
    methods:{
        add(){
            this.list.push({
                id: count++
            })
        },
        remove(){
            count--;
            this.list.pop()// 将数组最后一个元素剔除
        }
    }
}).mount("#app")

这样,添加和删除操作都有了对应的过渡效果,整个列表就好似 “活” 了起来。