该页面内容均来自vue.js官网(https://cn.vuejs.org/v2/guide/transitions.html#可复用的过渡),是对个人理解的总结,仅用于学习。
1. 多组件的过渡
过渡模式
in-out: 新元素先进行过渡,完成之后当前元素过渡离开。
out-in: 当前元素先进行过渡,完成之后新元素过渡进入。
如下(该例子来自 vue 官网上)
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
<title>多个组件的过渡</title>
<style media="screen">
* {
margin: 0;
padding: 0;
}
.component-fade-enter-active, .component-fade-leave-active {
transition: opacity 0.3s ease;
}
.component-fade-enter, .component-fade-leave-to {
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<input type="radio" @click="handleClick" name="a" checked="checked"><label>A</label>
<input type="radio" @click="handleClick" name="a"><label>B</label>
<transition name="component-fade" mode="out-in">
<component v-bind:is="view"></component>
</transition>
</div>
<script>
var vm = new Vue({
el: "#app",
data: {
view: 'v-a'
},
components: {
'v-a': {
template: '<div>Component A</div>'
},
'v-b': {
template: '<div>Component B</div>'
}
},
methods: {
handleClick: function () {
this.view = this.view === 'v-a' ? 'v-b' : 'v-a'
}
}
})
</script>
</body>
</html>
解释
1. 设置 v-enter-active (进入) 和 v-leave-active (退出) 状态动画 3s 透明度变化
2. 设置 v-enter(开始进入) 和 v-leave-to(退出结束) 透明度变为 0
3. input 中的 name 值相同时变为单选,checked 值为 checked 时,为默认被选值
4. mode 设置为 out-in,则之前元素先完成动画,新元素再完成动画
5. v-bind:is="view" 设置值为 view
6. this.view = this.view === 'v-a' ? 'v-b' : 'v-a' 两者之间切换
2. 列表的进入/离开过渡
如下(该例子来自 vue 官网上)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<title>列表的进入/离开过渡</title>
<style type="text/css">
.list-item {
display: inline-block;
margin-right: 10px;
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to {
opacity: 0;
transform: translateY(30px);
}
span {
font-family: KaiTi;
font-weight: 600;
color: #444;
font-size: 18px;
float: left;
margin-left: 10px;
list-style-type: none;
}
</style>
</head>
<body>
<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>
<script type="text/javascript">
var vm = 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)
}
}
})
</script>
</body>
</html>
解释
1. v-enter(开始进入) 和 v-leave-to(退出结束) 时的状态为下面 30px 透明,即新添
加的元素出现或删除的元素消失,会在列表下 30px 透明,由此时向上,并显示。
2. data 中是一个 9 个数的数组,下个数是第 10 个。
3. randomIndex 中产生 0~1 的随机数,之后乘以现在数组的长度,向下取整返回该值。
4. add 中向数组中 this.randomIndex() 的位置上添加新元素,删除为 0(即不删除),新元素值为 this.nextNum。
5. remove 中向数组中 this.randomIndex() 的位置上删除 1 个元素。
3. 列表的排序过渡
如下(该例子来自 vue 官网上)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<title>列表排序过渡</title>
<style type="text/css">
.flip-list-move {
transition: transform 1s;
}
li {
font-family: KaiTi;
font-weight: 600;
color: #444;
font-size: 18px;
float: left;
margin-left: 18px;
list-style-type: none;
}
</style>
</head>
<body>
<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>
<script type="text/javascript">
var vm = 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)
}
}
})
</script>
</body>
</html>
解释
1. 引用了 lodash 的动画库。
2. v-move 设置了动画的整体属性,动画时间 1s。
3. shuffle 中 this.items = _.shuffle(this.items) 数组的顺序被打乱,_shuffle 是 lodash库中的动画。
4. 动画过渡
如下(该例子来自 vue 官网上)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<title>动画过渡&动画队列</title>
<style type="text/css">
.list-complete-item {
transition: all 1s;
display: inline-block;
margin-right: 10px;
}
.list-complete-enter, .list-complete-leave-to {
opacity: 0;
transform: translateY(30px);
}
.list-complete-leave-active {
position: absolute;
}
span {
font-size: 18px;
color: #555;
font-weight: bolder;
font-family: KaiTi;
margin-left: 5px;
}
</style>
</head>
<body>
<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">
<span
v-for="item in items"
v-bind:key="item"
class="list-complete-item"
>
{{ item }}
</span>
</transition-group>
</div>
<script type="text/javascript">
var vm = 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)
}
}
})
</script>
</body>
</html>
解释
1. randomIndex,add,remove 列表的进入/离开过渡。
2. shuffle 列表的排序过渡。
5. 多维网格动画过渡
如下(该例子来自 vue 官网上)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<title>多维网格的动画过渡</title>
<style type="text/css">
.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;
}
.cells-move {
transition: transform 1s;
}
</style>
</head>
<body>
<div id="sudoku-demo" class="demo">
<button @click="shuffle">
shuffle
</button>
<transition-group name="cells" tag="div" class="container">
<div v-for="cell in cells" :key="cell.id" class="cell">
{{ cell.number }}
</div>
</transition-group>
</div>
<script type="text/javascript">
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>
解释
1. cell.number 中 number: index % 9 + 1 对 index 取余加1。
2. Array.apply(null, { length: 81 }) 第一个参数是对象,第二个参数是数组,该数组中并没有赋值。
3. .map 方法按照原始数组元素顺序依次处理元素。
6. 列表的交错过渡
如下(该例子来自 vue 官网上)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<title>列表的交错过渡</title>
<style type="text/css">
li {
font-size: 24px;
color: #444;
}
</style>
</head>
<body>
<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>
<script type="text/javascript">
var vm = 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 vim = this
return this.list.filter(function (item) {
return item.msg.toLowerCase().indexOf(vim.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 }
)
}, delay)
},
leave: function (el ,done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 0, height: 0 },
{ complete: done }
)
}, delay)
}
}
})
</script>
</body>
</html>
解释
1. v-for='(item, index) in computedList' 列表中的元素取自 computedList 函数中。
2. this.list.filter 对 list 数组进行过滤。
3. item.msg.toLowerCase().indexOf(vim.query.toLowerCase()) !== -1
toLowerCase() 将字符串转换为小写,indexOf 返回某个指定的字符串值在字符串中首次出现的位置,
这里的意思是将数组中的值转换为小写字符串,和 input 中填写的字符串转换为小写对比查找。
4. v-bind:data-index='index' 则每一个 li 标签中,存在一个 data-index 值,data-index 值会随
着 li 标签在数组中的位置改变。
5. var delay = el.dataset.index * 150;将 li 标签的 data-index 值乘于 150 毫秒,作为定时器
动画执行时间。
7. 动态过渡
如下(该例子来自 vue 官网上)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<title>动态过渡</title>
</head>
<body>
<div id="dynamic-fade-demo" class="demo">
Fade In: <input type="range" v-model="fadeInDuration" min="0" v-bind:max="maxFadeDuration">
Fade Out: <input type="range" v-model="fadeOutDuration" min="0" v-bind:max="maxFadeDuration">
<transition
v-bind:css='false'
v-on:defore-enter='beforeEnter'
v-on:enter='enter'
v-on:leave='leave'
>
<p v-if='show'>hello</p>
</transition>
<button
v-if='stop'
v-on:click='stop = false; show = false'
>
Start animating
</button>
<button
v-else
v-on:click='stop = true'
>
Stop it!
</button>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#dynamic-fade-demo',
data: {
show: true,
fadeInDuration: 1000,
fadeOutDuration: 1000,
maxFadeDuration: 1500,
stop: true
},
mounted: function () {
this.show = false
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
},
enter: function (el, done) {
var vim = this
Velocity(el,
{ opacity: 1 },
{
duration: this.fadeInDuration,
complete: function () {
done()
if (!vim.stop) vim.show = false
}
}
)
},
leave: function (el, done) {
var vim = this
Velocity(el,
{ opacity: 0 },
{
duration: this.fadeOutDuration,
complete: function () {
done()
vim.show = true
}
}
)
}
}
})
</script>
</body>
</html>
网友评论