在之前的文章中咱们都是应用 <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>