- 列表过渡
- 列表的进入/离开过渡
- 列表的排序过渡
- 列表的交错过渡
列表过渡
目前为止,关于过渡我们已经讲到:
- 单个节点
同一时间渲染多个节点中的一个那么怎么同时渲染整个列表,比如使用
v-for?在这种场景中,使用<transition-group>组件。在我们深入例子之前,先了解关于这个组件的几个特点:不同于
<transition>,它会以一个真实元素呈现:默认为一个<span>。你也可以通过tag特性更换为其他元素。- 过渡模式不可用,因为我们不再相互切换特有的元素。
- 内部元素 总是需要 提供唯一的
key属性值。 - CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
列表的进入/离开过渡
现在让我们由一个简单的例子深入,进入和离开的过渡使用之前一样的 CSS 类名。
<div id="list-demo" class="demo"><button v-on:click="add">Add</button><button v-on:click="remove">Remove</button><transition-group name="list" tag="p"><span v-for="item in items" v-bind:key="item" class="list-item">{{ item }}</span></transition-group></div>
new Vue({el: '#list-demo',data: {items: [1,2,3,4,5,6,7,8,9],nextNum: 10},methods: {randomIndex: function () {return Math.floor(Math.random() * this.items.length)},add: function () {this.items.splice(this.randomIndex(), 0, this.nextNum++)},remove: function () {this.items.splice(this.randomIndex(), 1)},}})
.list-item {display: inline-block;margin-right: 10px;}.list-enter-active, .list-leave-active {transition: all 1s;}.list-enter, .list-leave-to/* .list-leave-active for below version 2.1.8 */ {opacity: 0;transform: translateY(30px);}
1 2 3 4 5 6 7 8 9
这个例子有个问题,当添加和移除元素的时候,周围的元素会瞬间移动到他们的新布局的位置,而不是平滑的过渡,我们下面会解决这个问题。
列表的排序过渡
<transition-group> 组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move 特性,它会在元素的改变定位的过程中应用。像之前的类名一样,可以通过 name 属性来自定义前缀,也可以通过 move-class 属性手动设置。
v-move 对于设置过渡的切换时机和过渡曲线非常有用,你会看到如下的例子:
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script><div id="flip-list-demo" class="demo"><button v-on:click="shuffle">Shuffle</button><transition-group name="flip-list" tag="ul"><li v-for="item in items" v-bind:key="item">{{ item }}</li></transition-group></div>
new Vue({el: '#flip-list-demo',data: {items: [1,2,3,4,5,6,7,8,9]},methods: {shuffle: function () {this.items = _.shuffle(this.items)}}})
.flip-list-move {transition: transform 1s;}

这个看起来很神奇,内部的实现,Vue 使用了一个叫 FLIP 简单的动画队列使用 transforms 将元素从之前的位置平滑过渡新的位置。
我们将之前实现的例子和这个技术结合,使我们列表的一切变动都会有动画过渡。
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script><div id="list-complete-demo" class="demo"><button v-on:click="shuffle">Shuffle</button><button v-on:click="add">Add</button><button v-on:click="remove">Remove</button><transition-group name="list-complete" tag="p"><spanv-for="item in items"v-bind:key="item"class="list-complete-item">{{ item }}</span></transition-group></div>
new Vue({el: '#list-complete-demo',data: {items: [1,2,3,4,5,6,7,8,9],nextNum: 10},methods: {randomIndex: function () {return Math.floor(Math.random() * this.items.length)},add: function () {this.items.splice(this.randomIndex(), 0, this.nextNum++)},remove: function () {this.items.splice(this.randomIndex(), 1)},shuffle: function () {this.items = _.shuffle(this.items)}}})
.list-complete-item {transition: all 1s;display: inline-block;margin-right: 10px;}.list-complete-enter, .list-complete-leave-to/* .list-complete-leave-active for below version 2.1.8 */ {opacity: 0;transform: translateY(30px);}.list-complete-leave-active {position: absolute;}

需要注意的是使用 FLIP 过渡的元素不能设置为 display: inline 。作为替代方案,可以设置为 display: inline-block 或者放置于 flex 中
FLIP 动画不仅可以实现单列过渡,多维网格也同样可以过渡:

列表的交错过渡
通过 data 属性与 JavaScript 通信 ,就可以实现列表的交错过渡:
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script><div id="staggered-list-demo"><input v-model="query"><transition-groupname="staggered-fade"tag="ul"v-bind:css="false"v-on:before-enter="beforeEnter"v-on:enter="enter"v-on:leave="leave"><liv-for="(item, index) in computedList"v-bind:key="item.msg"v-bind:data-index="index">{{ item.msg }}</li></transition-group></div>
new Vue({el: '#staggered-list-demo',data: {query: '',list: [{ msg: 'Bruce Lee' },{ msg: 'Jackie Chan' },{ msg: 'Chuck Norris' },{ msg: 'Jet Li' },{ msg: 'Kung Fury' }]},computed: {computedList: function () {var vm = thisreturn this.list.filter(function (item) {return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1})}},methods: {beforeEnter: function (el) {el.style.opacity = 0el.style.height = 0},enter: function (el, done) {var delay = el.dataset.index * 150setTimeout(function () {Velocity(el,{ opacity: 1, height: '1.6em' },{ complete: done })}, delay)},leave: function (el, done) {var delay = el.dataset.index * 150setTimeout(function () {Velocity(el,{ opacity: 0, height: 0 },{ complete: done })}, delay)}}})

