(八)Vue - 过渡和动画
过滤的类名
vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。
Vue 提供了 transition 的封装组件,可以再某些条件下,给任何元素或组件添加进入或离开过渡动画。
学习过渡,我们必须要知道有哪些过渡的类名。
借用官方文档的一张图来讲解过渡的类名:
在dom进入/离开的过渡中,会有 6 个 class 切换,我们可以理解为dom进入和离开的过渡,会存在6个class的钩子。
- v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
- v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
- v-enter-to:定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
- v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
- v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
- v-leave-to:定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
<style>
/* v-enter 【这是一个时间点】 是进入之前,元素的起始状态,此时还没有开始进入 */
/* v-leave-to 【这是一个时间点】 是动画离开之后,离开的终止状态,此时,元素 动画已经结束了 */
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
/* v-enter-active 【入场动画的时间段】 */
/* v-leave-active 【离场动画的时间段】 */
/* 设置持续时间和动画函数 */
.v-enter-active,
.v-leave-active{
transition: all 0.8s ease;
}
</style>
<body>
<div id="app">
<input type="button" value="toggle" @click="flag=!flag">
<!-- 使用Vue提供的 transition 元素,把 需要被动画控制的元素,包裹起来 -->
<transition>
<h3 v-if="flag">这个标签,用于体验过渡动画</h3>
</transition>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
flag: false
}
});
</script>
</body>
上面的代码示例是一个简单的进入离开过渡示例,我们只需要再过渡类名上做手脚,即可实现过渡效果;
其实当插入或删除包含在 transition 组件中的元素时,Vue 将会自动嗅探目标元素是否应用了 CSS 过渡或动画,如果是,会在恰当的时机添加/删除 相应的CSS 类名。
对于这些在过渡中切换的类名来说,如果你使用一个没有名字的 ,则 v- 是这些类名的默认前缀。如果你使用了 ,那么 v-enter 会替换为 my-transition-enter,其它类名同理。
自定义过渡的类名
上述例子中官方预设的过渡类名不够灵活,我们也可以不必使用官方预设的类名,而是自定义任意的过渡类名,
下面我们可以通过以下属性来自定义过渡类名:
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)
这样非常方便我们结合第三方动画库使用,具体示例结合第三方类库解释。
使用第三方类实现过渡动画
由于vue支持自定义过渡类名,让我们非常方便的使用第三方动画类库,这里以animate.css的css动画库作为例子来介绍
送上官方链接:https://animate.style/
可以在官方链接里找寻自己想要的效果。
<!--导入动画库 -->
<link rel="stylesheet" href="./lib/animate.css">
<!-- 入场 bounceIn动画 离场 bounceOut动画 -->
<body>
<!-- 点击按钮,让 h3 显示,再点击,让 h3 隐藏 -->
<div id="app">
<input type="button" value="toggle" @click="flag=!flag">
<!-- 使用enter-active-class和leave-active-class属性,自定义我们的过渡类名,在这里使用动画库的类名 -->
<!-- 这里需要添加animated的基础动画类,不然动画不生效 -->
<transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut">
<h3 v-if="flag">这是一个H3</h3>
</transition>
<!-- 使用 :duration="毫秒值" 来统一设置 入场 和 离场 时候的动画时长 -->
<!-- 也可以直接将animated的基础动画类统一设置在元素上 -->
<transition enter-active-class="bounceIn" leave-active-class="bounceOut" :duration="200">
<h3 v-if="flag" class="animated">这是一个H3</h3>
</transition>
<!-- 使用 :duration="{ enter: 200, leave: 400 }" 来分别设置 入场的时长 和 离场的时长 -->
<transition
enter-active-class="bounceIn"
leave-active-class="bounceOut"
:duration="{ enter: 200, leave: 400 }">
<h3 v-if="flag" class="animated">这是一个H3</h3>
</transition>
</div>
动画的钩子函数
我们可以再transition组件的属性中添加钩子函数
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
<!-- ... -->
</transition>
对应的是Vue对象中methods属性的钩子函数,我们可以理解为动画的生命周期钩子;
每个钩子所对应的动画周期就是其对应的字面意思,非常容易理解,下面以一个简单的例子来学习动画的钩子函数。
<body>
<div id="app">
<input type="button" value="开始动画" @click="flag=!flag">
<!-- 使用 transition包裹需要执行动画的元素 -->
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div class="red-circle" v-show="flag"></div>
</transition>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
flag: false
},
methods: {
// 动画钩子函数的第一个参数:el,表示 要执行动画的那个DOM元素,是个原生的 JS DOM对象
beforeEnter(el){
// beforeEnter 表示动画入场之前,此时,动画尚未开始,可以 在 beforeEnter 中,设置元素开始动画之前的起始样式
// 设置动画起始位置
el.style.transform = "translate(0, 0)"
},
enter(el, done){
//此方法如果不写,则没有动画效果,其并无其它作用,理解为会强制动画刷新;
el.offsetWidth
// enter 表示动画 开始之后的样式,这里,可以设置元素完成动画之后的,结束状态
el.style.transform = "translate(150px, 450px)"
el.style.transition = 'all 1s ease'
// 这里的 done, 就是 afterEnter 这个函数,done 是 afterEnter 函数的引用,这里必须要调用done(),否则afterEnter会同步调用,afterEnter调用会稍延迟,显得动画不够连贯
done()
},
afterEnter(el){
// 动画完成之后,会调用 afterEnter
this.flag = !this.flag
}
}
});
</script>
</body>
列表动画
针对列表,我们需要使用 ransition-group 组件来实现动画,其用法与transition组件类似
<!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for 循环渲染出来的,不能使用 transition 包裹,需要使用 transitionGroup -->
<!-- 如果要为 v-for 循环创建的元素设置动画,必须为每一个 元素 设置 :key 属性 -->
<!-- 给 ransition-group 添加 appear 属性,实现页面刚展示出来时候,入场时候的效果 -->
<!-- 通过 为 transition-group 元素,设置 tag 属性,指定 transition-group 渲染为指定的元素,如果不指定 tag 属性,默认,渲染为 span 标签 -->
<transition-group appear tag="ul">
<li v-for="(item, i) in list" :key="item.id" @click="del(i)">
{{item.id}} --- {{item.name}}
</li>
</transition-group>
当列表里元素位置发生变更后,周围元素会瞬间移动到新的位置,这样整体效果会不够平滑和友好。
为解决这个问题,我们可以使用 v-move属性,其特性与其他过渡属性一样;
其内部的实现,Vue 使用了一个叫 FLIP 简单的动画队列,使用 transforms 将元素从之前的位置平滑过渡新的位置。
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateY(80px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.6s ease;
}
/* .v-move 和 .v-leave-active 配合使用,能够实现列表里动画元素周围的元素,也会有一个过渡动画移动到新的未知*/
.v-move {
transition: all 0.6s ease;
}
.v-leave-active{
position: absolute;
}