在之前的文章中咱们都是应用 <transition> 组件来实现过渡, 其次要用于单个节点、或同一时间渲染多个节点中的一个这两种状况。而对于整个列表(比方应用 v-for)的过渡,则须要应用本文介绍的 <transition-group> 组件。
四、列表过渡
1,<transition-group> 阐明
(1)不同于 <transition>
,<transition-group>
会以一个实在元素出现:默认为一个 <span>
(咱们能够通过 tag
个性更换为其余元素。)
(2)过渡模式不可用,因为咱们不再互相切换特有的元素。
(3)<transition-group>
的外部元素总是须要提供惟一的 key
属性值。
2,列表的进入、来到过渡
(1)效果图
- 点击“插入一个元素”按钮,会在下方随机地位插入一个新的数字方块,新方块在插入过程中会有过渡动画。
- 点击“移除一个元素”按钮,会随机删除下方的一个数字方块,该方块在移除过程中会有过渡动画。
(2)样例代码
<template> <div id="app"> <div id="list-demo" class="demo"> <button v-on:click="add">插入一个元素</button> <button v-on:click="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> </div></template> <script>export default { name: 'App', data: function(){ return { 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) }, }}</script> <style> /** 方块元素的款式 **/ .list-item { display: inline-block; margin-right: 10px; background-color: orange; width: 30px; height: 30px; line-height: 30px; text-align: center; color: #ffffff; } /** 插入过程 **/ .list-enter-active{ transition: all 1s; } /** 移除过程 **/ .list-leave-active { transition: all 1s; } /*** 开始插入、移除完结的地位变动 ***/ .list-enter, .list-leave-to { opacity: 0; transform: translateY(30px); }</style>
3,列表的排序过渡
(1)下面的样例有个问题:尽管新插入的元素或者被移除的元素有动画成果,但它四周的元素会霎时挪动到他们新布局的地位,而不是平滑的过渡。要解决这个问题则须要借助新增的 v-move
个性。
v-move 个性会在元素扭转定位的过程中利用,它像之前的类名一样:能够通过 name 属性来自定义前缀(比方 name="xxxx",那么对应的类名便是 xxx-move)也能够通过 move-class 属性手动设置自定义类名。
(2)这里对之前样例的 css 局部稍作批改,能够发现在插入或移出过程中,其它元素也会从原来的地位平滑过渡新的地位。
<style> /** 方块元素的款式 **/ .list-item { display: inline-block; margin-right: 10px; background-color: orange; width: 30px; height: 30px; line-height: 30px; text-align: center; color: #ffffff; } /** 插入过程 **/ .list-enter-active{ transition: all 1s; } /** 移除过程 **/ .list-leave-active { transition: all 1s; position: absolute; } /*** 开始插入、移除完结的地位变动 ***/ .list-enter, .list-leave-to { opacity: 0; transform: translateY(30px); } /*** 元素定位扭转时动画 ***/ .list-move { transition: transform 1s; }</style>
(3)Vue
应用了一个叫 FLIP 简略的动画队列实现排序过渡。所以即便没有插入或删除元素,对于元素程序的变动,也是反对过渡动画的。
<template> <div id="app"> <div id="list-demo" class="demo"> <button v-on:click="shuffle">乱序</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> </div></template> <script>export default { name: 'App', data: function(){ return { items: [1,2,3,4,5,6,7,8,9] } }, methods: { shuffle: function () { return this.items.sort(function(a,b){ return Math.random()>.5 ? -1 : 1;}) } }}</script> <style> /** 方块元素的款式 **/ .list-item { display: inline-block; margin-right: 10px; background-color: orange; width: 30px; height: 30px; line-height: 30px; text-align: center; color: #ffffff; } /*** 元素定位扭转时动画 ***/ .list-move { transition: transform 1s; }</style>
(4)FLIP 动画不仅能够实现单列过渡,多维网格也同样能够过渡:
<template> <div id="app"> <div id="list-demo" class="demo"> <button v-on:click="shuffle">乱序</button> <transition-group name="cell" tag="div" class="container"> <div v-for="cell in cells" :key="cell.id" class="cell"> {{ cell.number }} </div> </transition-group> </div> </div></template> <script>export default { name: 'App', data: function(){ return { cells: Array.apply(null, { length: 81 }) .map(function (_, index) { return { id: index, number: index % 9 + 1 } }) } }, methods: { shuffle: function () { this.cells.sort(function(a,b){ return Math.random()>.5 ? -1 : 1;}) } }}</script> <style> .container { display: flex; flex-wrap: wrap; width: 238px; margin-top: 10px; } .cell { display: flex; justify-content: space-around; align-items: center; width: 25px; height: 25px; border: 1px solid #aaa; margin-right: -1px; margin-bottom: -1px; } .cell:nth-child(3n) { margin-right: 0; } .cell:nth-child(27n) { margin-bottom: 0; } .cell-move { transition: transform 20s; }</style>
附:应用 js 钩子函数实现列表的交织过渡
咱们也能够通过 data
属性与 JavaScript
通信,实现列表的交织过渡。
1,效果图
(1)在上方输入框中输出内容时,下方的列表会实时筛选并显示出蕴含该文字的条目。
(2)同时在列表条目标显示或者移出过程中,会有相应的过渡动画。
2,样例代码
<template> <div id="app"> <div id="staggered-list-demo"> <input v-model="query"> <transition-group name="staggered-fade" tag="ul" v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave"> <li v-for="(item, index) in computedList" v-bind:key="item.msg" v-bind:data-index="index" >{{ item.msg }}</li> </transition-group> </div> </div></template> <script>import Velocity from 'velocity-animate' export default { name: 'App', data: function(){ return { query: '', list: [ { msg: 'Bruce Lee' }, { msg: 'Jackie Chan' }, { msg: 'Chuck Norris' }, { msg: 'Jet Li' }, { msg: 'Kung Fury' } ] } }, computed: { computedList: function () { var vm = this return this.list.filter(function (item) { return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1 }) } }, methods: { beforeEnter: function (el) { el.style.opacity = 0 el.style.height = 0 }, enter: function (el, done) { var delay = el.dataset.index * 150 setTimeout(function () { Velocity( el, { opacity: 1, height: '1.6em' }, { complete: done , duration: 20000 } ) }, delay) }, leave: function (el, done) { var delay = el.dataset.index * 150 setTimeout(function () { Velocity( el, { opacity: 0, height: 0 }, { complete: done , duration: 20000 } ) }, delay) } }}</script>