首页 > 编程笔记 > JavaScript笔记
阅读:342
Vue transition-group组件实现列表过渡动画
通过 transition 元素,可以实现单个节点和多个节点在同一时间渲染过渡,同样,也可以使用 transition-group 组件,实现一个列表中多项的过渡。
相对 transition,transition-group 有以下几个特点:
使用 CSS 类名,实现列表的进入/离开过渡,代码如下:
单击上面样例的 Shuffle 案例,会将数字随机打乱,但是很快就替换完成,没有动画的感觉。
在 transition-group 中有个 v-move 属性,能改变定位。开发人员通过给 v-move 属性设置过渡的切换时机和过渡曲线,就可以实现动态的定位过渡。v-move 名称的命名规则同 v-enter、v-enter-active 等属性的规则一样(默认为 v- 前缀,否则就以 transition-group 的 name 属性的值作为前缀)。
在上面样例的 style 中,添加如下代码的 CSS 类,单击 Shuffle 按钮,就可以体会到定位的动态过渡效果,代码如下:
Vue.js 使用了一个叫作 FLIP 的简单的动画队列,使用 transforms 将元素从之前的位置平滑过渡到新的位置。使用 FLIP 技术,可完成位置完美的平滑过渡,代码如下:
FLIP 不仅可以实现单列过渡,还可以实现多维网格过渡,代码如下:
通过 data attribute 与 JavaScript 通信,可以实现列表的交错过渡,代码如下:
相对 transition,transition-group 有以下几个特点:
- 与 transition 不同,它会以一个真实元素呈现,默认为 span,也可以通过 tag 属性指定。
- 在 transition-group 中不存在过渡模式,因为在列表过渡中不存在切换的离开/进入。
- 内部元素,必须有一个唯一的 key 属性值。
- CSS 过渡的类,将会应用到内部的元素中,而不是组/容器本身。
使用 CSS 类名,实现列表的进入/离开过渡,代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 引入 Vue.js --> <script src="../static/js/Vue.js" type="text/JavaScript"></script> <title>Demo vue</title> </head> <body> <!-- 定义 Vue.js 的视图 --> <div id="app"> <button v-on:click="add">Add</button> <button v-on:click="remove">Remove</button> <button @click="shuffle">Shuffle</button> <transition-group name="list" tag="div"> <span v-for="item in items" v-bind:key="item" class="list-item"> {{ item }} </span> </transition-group> </div> <script type="text/JavaScript"> // 创建 Vue.js 对象 const vm = new Vue({ el: "#app", 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); } } }); </script> <style> .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); } </style> </body> </html>通过代码可以了解,列表的过渡实现同单元素的过渡实现基本类似,除了将过渡元素改成了 transition-group 外。
单击上面样例的 Shuffle 案例,会将数字随机打乱,但是很快就替换完成,没有动画的感觉。
在 transition-group 中有个 v-move 属性,能改变定位。开发人员通过给 v-move 属性设置过渡的切换时机和过渡曲线,就可以实现动态的定位过渡。v-move 名称的命名规则同 v-enter、v-enter-active 等属性的规则一样(默认为 v- 前缀,否则就以 transition-group 的 name 属性的值作为前缀)。
在上面样例的 style 中,添加如下代码的 CSS 类,单击 Shuffle 按钮,就可以体会到定位的动态过渡效果,代码如下:
.list-move {
transition: transform 3s;
}
Vue.js 使用了一个叫作 FLIP 的简单的动画队列,使用 transforms 将元素从之前的位置平滑过渡到新的位置。使用 FLIP 技术,可完成位置完美的平滑过渡,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Vue.js -->
<script src="../static/js/Vue.js" type="text/JavaScript"></script>
<script src="../static/js/lodash.min.js" type="text/JavaScript"></script>
<title>Demo vue</title>
</head>
<body>
<!-- 定义 Vue.js 的视图 -->
<div id="app">
<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">
<span v-for="item in items" v-bind:key="item" class="list-complete-item">
{{ item }}
</span>
</transition-group>
</div>
<script type="text/JavaScript">
// 创建 Vue.js 对象
const vm = new Vue({
el: "#app",
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);
}
}
});
</script>
<style>
.list-complete-item {
transition: all 0.5s;
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;
}
</style>
</body>
</html>
需要注意的是使用 FLIP 过渡的元素不能被设置为 display:inline。作为替代方案,可以设置为 display:inline-block 或者放置于 flex 中。FLIP 不仅可以实现单列过渡,还可以实现多维网格过渡,代码如下:
<!DOCTYPE html>
<html>
<head>
<title>List Move Transitions Sudoku Example</title>
<script src="../static/js/Vue.js" type="text/JavaScript"></script>
<script src="./static/js/lodash.min.js" type="text/JavaScript"></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 0.5s;
}
</style>
</head>
<body>
<div id="sudoku-demo" class="demo">
<h1>Lazy Sudoku</h1>
<p>Keep hitting the shuffle button until you win.</p>
<button @click="shuffle">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>
<script>
new Vue({
el: "#sudoku-demo",
data: {
cells: Array.apply(null, { length: 81 }).map(function(_, index) {
return {
id: index,
number: (index % 9) + 1
};
})
},
methods: {
shuffle: function() {
this.cells = _.shuffle(this.cells);
}
}
});
</script>
</body>
</html>
通过 data attribute 与 JavaScript 通信,可以实现列表的交错过渡,代码如下:
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<div id="staggered-list-demo">
<input type="text" v-model="query">
<transition-group
name="staggered-fade"
tag="ul"
v-bind:class="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>
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 = 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" }, { duration: 300, complete: done });
}, delay);
},
leave: function(el, done) {
var delay = el.dataset.index * 150;
setTimeout(function() {
Velocity(el, { opacity: 0, height: 0 }, { complete: done });
}, delay);
}
}
});
ICP备案:
公安联网备案: