CSS动画及原理 过渡动画效果
transition
包裹的标签能设置动画效果。vue会自动地在一些时间点上,向transition
标签增加一些类名。
过渡的动画效果 通过C3中transition属性的形式实现
显示
- 被
transition
包裹,vue自动分析元素CSS样式然后构建一个动画流程:
动画被执行的一瞬间,往div上增加两个类名。
动画运行到第二帧,删除一个增加一个。
动画运行到结束的一瞬间。 - opacity透明度,原始默认值为1。动画运行到第二帧,移除了fade-enter,则opacity变为1,而此时fade-enter-to监听到fade-enter-to发生变化,则让其在3s内完成变化。
- transition起的名字是fade,所以样式表选择器前缀为fade,如果不起名字,默认为
v
隐藏
代码
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
/* 对opacity进行transition的监控,如果监控到opacity发生变化,会慢慢变化 */
}
<body>
<div id="root">
<transition name="fade">
<div v-if="show">hello world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
<script>
var vm=new Vue({
el:'#root',
data:{
show:true
},
methods: {
handleClick: function(){
this.show=!this.show
}
}
})
</script>
</body>
keyframse形式的C3动画
<style>
/* 定义keyframes形式的C3叫做bounce-in的动画效果 */
@keyframes bounce-in
{
0% {
transform:scale(0);
}
50% {
transform:scale(1.5);
}
100% {
transform:scale(1);
}
}
.fade-enter-active {
transform-origin: left center;
animation: bounce-in 1s;
}
.fade-leave-active {
transform-origin: left center;
animation: bounce-in 1s reverse;
}
选择器换个名字也可以,自己定义enter-activate-class的名字:
在Vue中使用Animate.css库
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./vue.js"></script>
<link rel="stylesheet" type="text/css" href="./animate.css">
</head>
<body>
<div id="root">
<transition
name="fade"
enter-active-class="animated swing"
leave-active-class="animated shake"
>
<!--自定义class名字 使用animated里的动画效果swing-->
<!-- 使用animated库里的动画效果 -->
<div v-show="show">hello world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
<script>
var vm=new Vue({
el:'#root',
data:{
show:true
},
methods: {
handleClick: function(){
this.show=!this.show
}
}
})
</script>
</body>
</html>
Vue中同时使用过渡和动画库
让hello world 第一次展示在页面上时也有动画→自定义一个类appear-active-class
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="./vue.js"></script>
<link rel="stylesheet" type="text/css" href="./animate.css">
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 5s;
}
</style>
</head>
<body>
<div id="root">
<transition
type="transition"
:duration="{enter:5000, leave:10000}"
name="fade"
appear
enter-active-class="animated swing fade-enter-active"
leave-active-class="animated shake fade-leave-active"
appear-active-class="animated swing"
>
<!-- type动画时长以transition为准 -->
<!-- 使用animated库里的动画效果 -->
<div v-show="show">hello world</div>
</transition>
<button @click="handleClick">切换</button>
</div>
<script>
var vm=new Vue({
el:'#root',
data:{
show:true
},
methods: {
handleClick: function(){
this.show=!this.show
}
}
})
</script>
</body>
</html>
Vue中的JS动画与Velocity.js的结合
通过Vue提供的钩子写JS动画
-
不仅CSS可以实现动画,JS也可以,VUE提供了很多JS动画的钩子。
-
before-enter会自动接受参数el,即为transition包裹的标签。
-
enter接受两个参数,done为回调函数,当动画执行结束要调用一下回调函数,相当于告诉vue,动画已经执行完了。然后vue就会自动触发一个事件:
-
after-enter
-
出场动画和入场动画类似,把enter换成leave。
引入Velocity动画库
<!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">
<script src="./vue.js"></script>
<script src="./velocity.js"></script>
<title>Document</title>
</head>
<body>
<div id="root">
<transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter">
<div v-show="show">Hello World</div>
</transition>
<button @click="handleClick">toggle</button>
</div>
<script>
var vm = new Vue({
el: "#root",
data: {
show: true
},
methods: {
handleClick: function () {
this.show = !this.show
},
handleBeforeEnter: function (el) {
el.style.opacity = 0;
},
handleEnter: function (el, done) {
Velocity(el, {
opacity: 1
}, {
duration: 1000,
complete: done
})
},
handleAfterEnter: function (el) {
console.log('over');
}
},
})
</script>
</body>
</html>
Vue中多个元素或组件的过渡动画
元素之间的过渡动画
- vue切换两个元素的时候,会尽量的复用DOM,要给两个div不同的key值,才不会自动复用DOM。
- transition的属性mode设置元素切换的效果。
in-out
先显示 再隐藏out-in
先隐藏 再显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="./vue.js"></script>
<title>Document</title>
<style>
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-enter-active,
.v-leave-active{
transition: opacity 1s;
}
</style>
</head>
<body>
<div id="root">
<transition mode="out-in">
<div v-if="show" key="Hello">Hello World</div>
<div v-else key="bye">Bye World</div>
</transition>
<button @click="handleClick">toggle</button>
</div>
<script>
var vm = new Vue({
el: "#root",
data: {
show: true
},
methods: {
handleClick: function () {
this.show = !this.show
}
}
})
</script>
</body>
</html>
组件之间的过渡动画——动态组件
动态组件通过标签component
定义,属性is
让组件和对应的组件名绑定。
<body>
<div id="root">
<transition mode="out-in">
<component :is="type"></component>
</transition>
<button @click="handleClick">toggle</button>
</div>
<script>
Vue.component('child', {
template: '<div>child</div>'
})
Vue.component('child-one', {
template: '<div>child-one</div>'
})
var vm = new Vue({
el: "#root",
data: {
type: 'child'
},
methods: {
handleClick: function () {
this.type = this.type === 'child' ? 'child-one' : 'child';
}
}
})
</script>
</body>
Vue中的列表过渡
-
尽量不要使用index作为key值
-
transition-group
标签 -
div列表循环过后会变成几个div,里边都是hello world,在最外层加了一个transition-group,相当于在每个div标签外加了一个transition。把列表的过渡转化为单个元素的过渡,Vue动态找到时间点,增加一些class的名字。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="../vue.js"></script> <style> .v-enter, .v-leave-to{ opacity: 0; } .v-enter-active, .v-leave-active { transition: opacity 1s; } </style> </head> <body> <div id="root"> <transition-group> <div v-for="item of list" :key="item.id"> {{item.title}} </div> </transition-group> <button @click="handleBtnClick">Add</button> </div> <script> var count = 0; var vm = new Vue({ el: "#root", data: { list: [] }, methods: { handleBtnClick: function () { this.list.push({ id: count++, title: 'hello world' }) } } }) </script> </body> </html>
Vue中的动画封装
如何进行动画封装,让动画变得可复用。
封装一个组件,利用插槽
<!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">
<script src="../vue.js"></script>
<title>Document</title>
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 1s;
}
</style>
</head>
<body>
<div id="root">
<fade :show="show">
<!-- 插槽 -->
<div>Hello World</div>
</fade>
<fade :show="show">
<!-- 插槽 -->
<div>Hi</div>
</fade>
<button @click="handleClick">toggle</button>
</div>
<script>
// 封装一个组件
Vue.component('fade',{
props:['show'],
template:
`
<transition name="fade">
<slot v-if="show"></slot>
</transition>
`
})
var vm = new Vue({
el: "#root",
data: {
show: false
},
methods: {
handleClick: function () {
this.show = !this.show
}
},
})
</script>
</body>
</html>
把动画样式也封装了,用JS写动画
<!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">
<script src="../vue.js"></script>
<title>Document</title>
</head>
<body>
<div id="root">
<fade :show="show">
<!-- 插槽 -->
<div>Hello World</div>
</fade>
<fade :show="show">
<!-- 插槽 -->
<div>Hi</div>
</fade>
<button @click="handleClick">toggle</button>
</div>
<script>
// 封装一个组件 动画通过JS来写 完整把所有动画实现封装到一个组件里边
Vue.component('fade',{
props:['show'],
template:
`
<transition @before-enter="handleBeforeEnter" @enter="handleEnter">
<slot v-if="show"></slot>
</transition>
`,
methods: {
handleBeforeEnter: function (el) {
el.style.color='red'
},
handleEnter: function (el, done) {
setTimeout(()=>{
el.style.color = 'green'
done();//动画执行完了要调用done函数
},2000)
}
}
})
var vm = new Vue({
el: "#root",
data: {
show: false
},
methods: {
handleClick: function () {
this.show = !this.show
}
}
})
</script>
</body>
</html>
动态过渡、状态过渡...... 见Vue官网文档