Vue.js第4课-Vue中的动画特效(part01)
一、Vue 中的 css 动画原理
先来实现一个非常简单的功能,通过点击按钮控制文本的展示与否。
<div id="app">
<button @click="clickFun">切换</button>
<div v-if="show">Hello World!</div>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
下面,我想实现一个动画的功能,“Hello World!” 显示和隐藏的时候,能够有一个渐隐渐现的动画效果。首先需要在 “Hello World!” 这个 div 外层包裹一个 transition 标签,这个标签的意思是他包裹的元素有一个动画效果,可以给 transition 这个标签起一个名字,例如 name="fade",这个名字可以随意起。我们还要把 transition 过渡动画的原理讲清楚。
在进入/离开的过渡中,会有 6 个 class 切换,Vue.js 官方文档是这样描述这 6 个 class 的:
1、v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
2、v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
3、v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
4、v-leave: 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
5、v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
6、v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
根据上边的 class 我们可以给元素添加一下过渡的样式:
<style>
/* 进入 */
.fade-enter {
opacity: 0
}
.fade-enter-active {
transition: opacity 2s
}
</style>
<div id="app">
<button @click="clickFun">切换</button>
<transition name="fade">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
上面代码,在第一次点击后,元素消失,再次点击,元素渐渐显示出来,可以看到控制台中给该元素添加了两个样式名,分别是 fade-enter-active 和 fade-enter-to,然后在 2s 后消失了,所以出现了渐现的效果。这两个 class 就是上边列出的 2 和 3 class。此时进入的过渡实现了,我们再添加一下离开的过渡。
<style>
/* 进入 */
.fade-enter {
opacity: 0
}
.fade-enter-active {
transition: opacity 2s
}
/* 离开 */
.fade-leave-to {
opacity: 0
}
.fade-leave-active {
transition: opacity 2s
}
</style>
<div id="app">
<button @click="clickFun">切换</button>
<transition name="fade">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
元素离开时,也被添加了两个 class,分别是 fade-leave-active 和 fade-leave-to,也就是上边列出的 5 和 6 class。
面代码就实现了一个渐隐渐现的动画效果。在 transition 也可以不传入 name,样式名中的 fade 换成 v 就可以,也可以把相同属性的样式放在一起:
<style>
.v-enter,
.v-leave-to {
opacity: 0
}
.v-enter-active,
.v-leave-active {
transition: opacity 2s
}
</style>
<div id="app">
<button @click="clickFun">切换</button>
<transition>
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
二、在 Vue 中使用 Animate.css 库
这一节来讲解 Vue 中更复杂的动画效果。首先进入上一节最终的那段代码,并对这段代码进行一个变更。上一节是讲了 transition 的使用方法,这一节看一下 keyframes 形式的动画。
回忆一下 fade-enter-active 和 fade-leave-active 这两个 class 是什么时候生效的,当 div 标签在显示的这个过程中,fade-enter-active 是一直存在的,当他在隐藏的过程中,fade-leave-active 是一直存在的,根据这个特性可以这样写动画效果:
<style>
@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;
}
</style>
<div id="app">
<button @click="clickFun">toggle</button>
<transition name="fade">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
上面代码定义了一个 keyframes 的一个 CSS3 动画 bounce-in,分别设置 0%、50%、100% 时 的状态,然后在 fade-enter-active 和 fade-leave-active 中就可以用这个动画了。打开页面可以看到,点击 toggle,隐藏时候有放大缩小的效果,显示的时候也有放大缩小的效果。
上面就讲解了在 Vue 中如何使用 keyframes 这种形式的 CSS3 动画。接着再讲一个知识点,当你使用 transition 标签的时候,给了一个 name="fade",那么他就会都自动的添加 fade-enter-active 和 fade-leave-active 这样的 class 名字。那我能不能定义一个就叫 enter 或 leave 这样的一个名字,不用他默认提供的命名的规范?是可以的,如果想这么写,只需要在 transition 外面自定义这个 class 名字,如下面代码:
<style>
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
.enter {
transform-origin: left center;
animation: bounce-in 1s;
}
.leave {
transform-origin: left center;
animation: bounce-in 1s reverse;
}
</style>
<div id="app">
<button @click="clickFun">change</button>
<transition name="fade" enter-active-class="enter" leave-active-class="leave">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
可以看到效果是一样的,不会有任何问题,到这里就可以知道,其实你可以自定义添加的 class 名字。
现在既然可以自定义 fade-enter-active 和 fade-leave-active 名字,那借助这个功能我们就可以在我们的 Vue 项目里使用比较流行的 animate.css 库了,我们可以进入 animate.css 官网,在这里去查看对应动画的 class 名,然后添加 class 名。
下载 animate.css 文件并引用,我直接用了 BootCDN 的方式在项目中引用了 animate.css。引用了 animate.css 我就不需要自己写动画效果了,然后在入场动画和出场动画的 class 中添加 animated,并在后边更上对应动画效果的 class 名,例如下面代码:
<link href="https://cdn.bootcss.com/animate.css/3.7.0/animate.css" rel="stylesheet">
<div id="app">
<button @click="clickFun">change</button>
<transition name="fade" enter-active-class="animated bounce" leave-active-class="animated flash">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
如果想使用 animate.css 这个库,有几点需要注意:第一点是你必须使用自定义 class 名字的形式来使用 animate.css,第二是 class 类里面必须得包含一个 animate 这样一个具体的类,然后根据需求的不同添加不同动画的类名。
三、在 Vue 中同时使用过渡和动画
我们在上一节最终的代码上看一下,注意要引入 animate.css。使用 animate.css 和 @keyframes 是没有区别的,animate.css 其实就是一个封装。
<div id="app">
<button @click="clickFun">toggle</button>
<transition name="fade" enter-active-class="animated swing" leave-active-class="animated flash">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
当我们打开页面的时候,也就是元素第一次显示的时候,其实这个动画并没有被添加上,点击之后才会被添加上。那如果我想在元素第一次显示的时候,我的这个 “Hello Word!” 也具备动画效果,应该怎么做呢?
我们在 transition 中增加一个自定义名字叫做 appear-active-class="animated swing",就这样写是不行的,如果想使用 appear-active-class 的话,记得在上面再写一个属性叫做 appear,意思是第一次显示这个内容的时候,也有一个动画效果,它的动画效果是使用了 animated 库中的一个动画。
<div id="app">
<button @click="clickFun">toggle</button>
<transition name="fade" appear enter-active-class="animated swing" leave-active-class="animated jello"
appear-active-class="animated jello">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
这个时候刷新页面,可以看到第一次显示元素的时候就有一个动画效果,隐藏没问题,显示也没问题,都有动画效果。
在上面这个例子中,实际上我们只用到了一种动画,就是 animate.css 库提供的动画。假设入场动画不仅有 css3 的动画效果,还有一个过渡的动画效果,怎么做呢?
在 enter-active-class 中添加一个 fade-enter-active,在 leave-active-class 中添加一个 fade-leave-active,然后给新添加的这两个 class 名添加属性,回忆一下第一节添加 transition 的方法。
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
}
</style>
<div id="app">
<button @click="clickFun">toggle</button>
<transition name="fade" appear enter-active-class="animated swing fade-enter-active"
leave-active-class="animated jello fade-leave-active" appear-active-class="animated swing">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
打开页面点击按钮可以看到,此时元素既有 animate 动画效果,也有 transition 透明度的变化效果,所以把两个动画结合到了一起做了一个使用。
但是会发现这样一个问题,opacity 动画执行的是 3s,但是 animate.css 这个动画执行的是几秒呢?我们可以从 animate.css 源码中查看一下:
可以看到 animate.css 动画执行的时间是 1s,那整个的动画效果到底是怎么算呢?是 1s 所有动画都结束,还是 3s 所有动画都结束?Vue 也不清楚哪一个是结束时长,这个时候我们可以手动的去设置,我们现在已 3s 这个比较长的时间作为动画时间,直接在 transition 标签中写 type="transition" 就可以了:
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
}
</style>
<div id="app">
<button @click="clickFun">toggle</button>
<transition type="transition" name="fade" appear enter-active-class="animated swing fade-enter-active"
leave-active-class="animated jello fade-leave-active" appear-active-class="animated swing">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
它的意思是,我的这个动画既有 animate 就是普通的这种 @keyframe 形式的动画,又有 transition 这种形式的动画,我的动画时长以 transition 的动画时长为准,他就会以 3s 作为整个动画的执行时间。到页面上,点击按钮,可以看到 3s 动画结束。这样我们就确定了我们动画的播放时长。
现在是以过渡效果的时长作为动画的总时长,那能不能我自己定义一个动画执行的总时长呢?这个时长是可以进行自定义的,可以在 transition 标签中这么写:
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
}
</style>
<div id="app">
<button @click="clickFun">toggle</button>
<transition :duration="5000" name="fade" appear enter-active-class="animated swing fade-enter-active"
leave-active-class="animated jello fade-leave-active" appear-active-class="animated swing">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
上面代码,我在 transition 标签中添加了一个 :duration 属性,值设置为 5000,意思是我让这个动画的执行时长是 5s。回到浏览器上,怎么才能看到效果呢?我们可以查看元素,点击 toggle,3s 后元素其实已经隐藏掉了,但是这个动画并没有执行完,fade-leave-active 和 fade-leave-to 还都在,等 5s 后才会消失。
现在是自定义了一个动画的时长,其实这个时长还可以设置的复杂一点,可以设置一个入场动画的时长和一个出场动画的时长,例如入场设置为 5s,出场设置为 10s。
<style>
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 3s;
}
</style>
<div id="app">
<button @click="clickFun">toggle</button>
<transition :duration="{enter:5000,leave:10000}" name="fade" appear
enter-active-class="animated swing fade-enter-active" leave-active-class="animated jello fade-leave-active"
appear-active-class="animated swing">
<div v-if="show">Hello World!</div>
</transition>
</div>
<script>
var app = new Vue({
el: "#app",
data: {
show: true
},
methods: {
clickFun: function () {
this.show = !this.show
}
}
})
</script>
打开页面,点击按钮,查看元素,可以看到元素入场的时长为 5s,出场的时长为 10s。