Vue中如何为v-for渲染的组件添加过渡实现卡片向上轮播效果
问题原因
核心是Vue的列表就地更新优化策略:你当前使用数组内容作为key,旋转数组时Vue识别到对应key的节点依然存在,会直接移动复用真实DOM,不会触发组件重新挂载,因此你写在Box组件内部的单节点transition不会触发进入动画。此外你之前使用transition-group没生效,是因为缺少了控制节点移动过程的v-move过渡类,也没有处理列表项离开时的布局占位问题。
具体解决方案
1. 调整HTML结构
外层用<transition-group>包裹列表,去掉Box组件内部的单节点transition:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <div class="hero"> <box :achievement="achievements[0]"></box> </div> <div class="box-wrapper"> <div><button @click="leftRotateArr">Up</button></div> <!-- 用transition-group包裹列表 --> <transition-group name="slide-up" tag="div"> <box v-for="achievement in achievements" :achievement="achievement" :key="achievement"></box> </transition-group> </div> </div>
2. 简化Box组件代码
移除内部的transition,直接返回卡片节点:
var Box = { props: ['achievement'], template: '<div class="box">{{achievement}}</div>', }; new Vue({ el: '#app', data: { achievements: ['Title1', 'Title2', 'Title3', 'Title4'] }, created() { this.autoRotateArr(); }, components: { 'box': Box }, methods: { leftRotateArr() { this.achievements.push( this.achievements.shift() ) }, autoRotateArr() { this.interval = setInterval(() => this.leftRotateArr(), 3000); } } })
3. 补全过渡CSS
新增移动过渡、离开过渡,同时给离开的元素设置绝对定位避免占位:
.box-wrapper { display: flex; flex-direction: column; margin: 0 auto; padding: 50px; position: relative; /* 给绝对定位的离开元素做定位参照 */ } .box { height: 50px; background-color: orange; margin: 10px 0; } /* 进入、离开、移动过程都加过渡 */ .slide-up-enter-active, .slide-up-leave-active, .slide-up-move { transition: all 666ms cubic-bezier(0, 0, 1, 1); } /* 进入时从下方滑入 */ .slide-up-enter { transform: translateY(50px); opacity: 0; } /* 离开时向上滑出 */ .slide-up-leave-active { position: absolute; left: 50px; right: 50px; } .slide-up-leave-to { transform: translateY(-70px); opacity: 0; }
修改后旋转数组时,最顶部的卡片会向上滑出消失,剩下的所有卡片会同步向上滑动,底部同时滑入新的卡片,即可实现整体上滑轮播效果。
内容的提问来源于stack exchange,提问作者Anish
相关产品推荐
相关产品推荐

