第4章 Vue 过渡和动画
文章目录
4.1 过渡和动画基础
transition 组件
注 意 t r a n s i t i o n 同 一 时 间 只 能 显 示 一 个 元 素 注意\ transition\ 同一时间只能显示一个元素 注意 transition 同一时间只能显示一个元素
把需要添加过渡的 div 放入其中,用 name 设置前缀(默认前缀是 v)
<transition name='box'>
<div class='chart' v-if='isShow'></div>
</transition>
初始状态
<style>
.chart {
width: 200px;
height: 50px;
background-color: orangered;
}
.box-enter-active, .box-leave-active {
transition: width 3s;
}
.box-enter, .box-leave-to {
width: 0px;
}
.box-enter-to, .box-leave {
width: 200px;
}
</style>
自定义类名
通 过 属 性 来 设 置 ( 自 定 义 类 名 结 合 a n i m a t e . c s s 动 画 库 ) 通过属性来设置(自定义类名结合\ animate.css\ 动画库) 通过属性来设置(自定义类名结合 animate.css 动画库)
<transition enter-active-class='animated bounceInLeft'
leave-active-class='animated bounceOutLeft'>
<p v-if='isShow'>hello world</p>
</transition>
a p p e a r 初 始 渲 染 动 画 ( 每 次 刷 新 页 面 ) appear\ 初始渲染动画(每次刷新页面) appear 初始渲染动画(每次刷新页面)
<link rel="stylesheet" href="animate.css">
<transition appear appear-class='animated swing'
appear-to-class='animated bounceIn'
appear-active-class='animated bounceOut'>
<div v-if='isShow's>过渡文字</div>
</transition>
使用@keyframes 创建 CSS 动画
动 画 和 过 渡 的 区 别 就 在 于 , 动 画 可 以 改 中 间 内 容 , 一 帧 一 帧 的 改 动画和过渡的区别就在于,动画可以改中间内容,一帧一帧的改 动画和过渡的区别就在于,动画可以改中间内容,一帧一帧的改
<style>
/* .bounce */
.box-enter-active {
animation: Ami 2.5s; /* 动画时间 */
}
.box-leave-active {
animation: Ami 2.5s;
}
@keyframes Ami {
0% {transform: scale(0); background: orangered;}
20% {transform: scale(1); background: burlywood;}
40% {transform: scale(1.25); background: blue;}
60% {transform: scale(1.3); background: burlywood;}
80% {transform: scale(1.25); background: orangered;}
100% {transform: scale(1); background: orange;}
}
Vue 结合 Velocity.js 实现动画
用 了 钩 子 函 数 和 V e l o c i t y . j s 用了钩子函数 和\ Velocity.js 用了钩子函数和 Velocity.js
<script src="velocity.js"></script>
<transition @before-enter='beforeEnter' @enter='enter'
@leave='leave' v-bind:css='false'>
<p v-if='isShow'>demo 05</p>
</transition>
<script>
methods: {
beforeEnter(el) {
el.style.opacity = 0
el.style.transformOrigin = 'left' // 旋转元素的基点位置
el.style.color = 'red'
},
enter(el, done) {
Velocity(el, {opacity: 1, fontSize: '1.4em'}, {duration: 300}) // duration 执行时间
Velocity(el, {fontSize: '1em'}, {complete: done})
},
leave(el, done) {
Velocity(el, {translateX: '15px', rotateZ: '50deg'}, {duration: 3000})
Velocity(el, {rotateZ: '100deg'}, {loop: 2}) // 重复 2 次
Velocity(el, {rotateZ: '45deg', translateY: '30px', translateX: '30px',
opacity: 0}, {complete: done})
}
} // 哦,天爷,自己琢磨吧。。(这个 velocity 用的是老版本的)
使 Vue 跳过 CSS 的检测
v-bind:css="false"
4.2 多个元素过渡
不同签名元素的过渡
用 v − i f 和 v − e l s e 用\ v-if\ 和\ v-else 用 v−if 和 v−else
<transition>
<div v-if='1 > 0'>div</div>
<p v-else>p</p>
</transition>
相同签名元素的过渡
需 要 k e y , 不 然 无 法 区 分 相 同 签 名 的 元 素 需要\ key,不然无法区分相同签名的元素 需要 key,不然无法区分相同签名的元素
<button @click='isShow = !isShow'>change isShow</button>
<transition name='fade'>
<button v-if='isShow' key='save'>save</button>
<button v-else key='edit'>edit</button>
</transition>
通 过 改 k e y 的 值 , 实 现 按 钮 切 换 通过改\ key\ 的值,实现 按钮切换 通过改 key 的值,实现按钮切换
<button v-bind:key='isShow'>{{isShow ? 'true' : 'false'}} </button>
还 可 以 这 样 用 v − i f 还可以这样用\ v-if 还可以这样用 v−if
<div class="red" v-if="show == 'A'" key="A"></div>
<div class="blue" v-if="show == 'B'" key="B"></div>
<div class="yellow" v-if="show == 'C'" key="C"></div>
<script>
showNum () {
if (this.show == 'A') { return this.show = 'B' }
} // 切换 show
还 可 以 用 c o m p u t e d 计 算 属 性 还可以用\ computed\ 计算属性 还可以用 computed 计算属性
{{showNum}}
computed: {
showNum() {
switch(this.isShow) {
case 'A': return 'a'
// 不再赘述
过渡模式
为 实 现 有 序 过 渡 , 加 了 m o d e 属 性 为实现有序过渡,加了\ mode\ 属性 为实现有序过渡,加了 mode 属性
mode 属性有两个值:in-out 和 out-in,一般用 out-in,先出后进(即当前元素先过渡,然后新元素过渡进入)
<transition name='fade' mode='out-in'>
<button v-bind:key='isOff' @click='isOff = !isOff'>
{{isOff ? 'Off' : 'On'}}
</button>
</transition>
// 用了 mode 和 out-in 以后,很丝滑
4.3 多个组件过渡
不 需 要 用 k e y 特 性 , 用 动 态 组 件 即 可 ( 即 i s 属 性 ) 不需要用\ key\ 特性,用动态组件即可(即\ is\ 属性) 不需要用 key 特性,用动态组件即可(即 is 属性)
// 主要就是用的 is 切换的组件
<style>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s ease;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>
<body>
<div id='app'>
<a href="javascript:;" @click='compontentName="example1"'>login</a>
<a href="javascript:;" @click='compontentName="example2"'>register</a>
<transition name='fade' mode='in-out'>
<component v-bind:is='compontentName'></component>
</transition>
</div>
<template id='ex1'> <span>login component</span> </template>
<template id='ex2'> <span>register component</span> </template>
<script>
Vue.component('example1', {template: '#ex1'})
Vue.component('example2', {template: '#ex2'})
var vm = new Vue({
el: '#app',
data: { compontentName: '' }
})
</script>
</body>
4.4 列表过渡
前面的都是 渲染单个元素或同时渲染多个元素中的一个,不适用于列表过渡
列表的进入和离开过渡
列 表 过 渡 用 v − f o r 和 t r a n s i t i o n − g r o u p 列表过渡用\ v-for\ 和\ transition-group 列表过渡用 v−for 和 transition−group
.list-item {
display: inline-block; margin-right: 10px; background-color: orangered;
border-radius: 50%; width: 25px; height: 25px; text-align: center;
line-height: 25px; color: #fff;
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to {
opacity: 0;
transform: translateY(30px)
}
<transition-group name='list' tag='div'>
<span v-for='item in items' v-bind:key='item' class='list-item'>
{{item}}
</span>
</transition-group>
data: {
items: [1, 2, 3, 4, 5],
nextNum: 6
},
methods: {
randomIndex() {
return Math.floor(Math.random() * this.items.length) // 0-1 之间的随机数
},
add() {
this.items.splice(this.randomIndex(), 0, this.nextNum++) // 删除 0 个
},
remove() {
this.items.splice(this.randomIndex(), 1)
}
}
列表的排序过渡
为 了 实 现 平 滑 过 渡 , 用 v − m o v e ( V u e 采 用 了 F L I P 技 术 , 动 画 更 流 畅 ) 为了实现平滑过渡,用\ v-move\ (Vue\ 采用了\ FLIP\ 技术,动画更流畅) 为了实现平滑过渡,用 v−move (Vue 采用了 FLIP 技术,动画更流畅)
.list-leave-active {
transition: all 1s;
position: absolute; // leave 这里要加一个绝对定位,否则不平滑
}
.list-move {
transition: transform 1s;
}
- 效果图:
利用 lodash.js 实现洗牌功能
<script src="lodash.js"></script>
<script>
shuffle() {
this.items = _.shuffle(this.items)
}
- 效果图:
列表的交错过渡
钩 子 函 数 结 合 V e l o c i t y . j s 实 现 搜 索 功 能 钩子函数结合\ Velocity.js\ 实现搜索功能 钩子函数结合 Velocity.js 实现搜索功能
<input type="text" placeholder="please enter what you are looking for:" v-model='query'>
<transition-group name='item' tag='ul' @before-enter='beforeEnter' @enter='enter'
@leave='leave' :css='false'>
<li v-for='(item, index) in ComputedList' :key='item.msg' :data-index='index'>
{{item.msg}}
</li>
</transition-group>
<script>
data: {
query: '',
items: [
{msg: 'zhangsan'}, {msg: 'lisi'}, {msg: 'zhangfangfang'},
{msg: 'wanglinlin'}, {msg: 'fengyuan'}
]
},
computed: {
ComputedList() {
var content = this.query
var nameList = this.items
return nameList.filter(function (item) {
return item.msg.toLowerCase().indexOf(content.toLowerCase()) !== -1
}) // 利用计算属性 返回过滤后的列表(研究下这个 return)
}
},
methods: {
beforeEnter(el) {
el.style.opacity = 0
el.style.height = 0
},
enter(el, done) {
var delay = el.dataset.index * 150
setTimeout(function() {
Velocity(el, {opacity: 1, height: '1.6em'}, {complete: done})
}, delay)
},
leave(el, done) {
var delay = el.dataset.index * 150
setTimeout(function() {
Velocity(el, {opacity: 0, height: 0}, {complete: done})
}, delay)
}
}
// 这样看来,写的时候可以只用三个钩子函数,就可以把进出的过渡写完(无 css 参与,用的 Velocity.js)
// 还是用 css 吧,只需给 v-enter-active & v-leave-active 写个 transition,
// 以及给 v-enter & v-leave-to 写个 opacity 即可
- 效果图:
可复用的过渡
t e m p l a t e 方 式 实 现 过 渡 的 封 装 template\ 方式实现过渡的封装 template 方式实现过渡的封装
就是写组件模板里面,用插件 slot 显示列表
<fade :query='query' :items='items'>
<li v-for='(item, index) in ComputedList' :key='item.msg' :data-index='index'>
{{item.msg}}
</li>
</fade>
<template id="temp">
<transition-group name='item' tag='ul' @before-enter='beforeEnter' @enter='enter'
@leave='leave' :css='false'>
<!-- <li v-for='(item, index) in ComputedList' :key='item.msg' :data-index='index'>
{{item.msg}}
</li> 用 slot -->
<slot></slot>
</transition-group>
</template>
<script>
Vue.component('fade', {
props: ['query', 'items'],
template: '#temp',
methods: {
beforeEnter(el) {
el.style.opacity = 0
el.style.height = 0
},
enter(el, done) {
var delay = el.dataset.index * 150
setTimeout(function() {
Velocity(el, {opacity: 1, height: '1.6em'}, {complete: done})
}, delay)
},
leave(el, done) {
var delay = el.dataset.index * 150
setTimeout(function() {
Velocity(el, {opacity: 0, height: 0}, {complete: done})
}, delay)
}
}
})
函 数 式 组 件 方 式 , 就 是 用 r a n d e r 函 数 来 实 现 函数式组件方式,就是用\ rander\ 函数来实现 函数式组件方式,就是用 rander 函数来实现
改一下 script 的内容为如下即可,效果如前(用了 render)
<script>
Vue.component('fade', {
functional: true, // 标记 fade 组件为函数式组件
props: ['query', 'items'],
render(h, ctx) {
var data = {
props: {
tag: 'ul', // 默认 span
css: false
},
on: {
beforeEnter(el) {
el.style.opacity = 0
el.style.height = 0
},
enter(el, done) {
var delay = el.dataset.index * 150
setTimeout(function() {
Velocity(el, {opacity: 1, height: '1.6em'}, {complete: done})
}, delay)
},
leave(el, done) {
var delay = el.dataset.index * 150
setTimeout(function() {
Velocity(el, {opacity: 0, height: 0}, {complete: done})
}, delay)
}
}
}
return h('transition-group', data, ctx.children)
}
})
E n d . End. End.