vue过度动画详解
vue过度&动画详解
我下面使用的是vue2框架
我完全按照vue2文档目录来做详解的。注意是vue2文档、注意是vue2文档、注意是vue2文档
目录
- 1.过渡模式
单标签或单组件的过渡
vue过度与动画:过渡就是css的transition属性,动画是animation属性
Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
条件渲染 (使用 v-if)
条件展示 (使用 v-show)
动态组件
组件根节点
注意:行内标签如果是使用css transform属性来进行过渡和动画,是不会有效果的,css本来就是这样的,transform属性只能用于块级或行内块标签
过渡的类名、css过渡
Vue封装了transition组件,这是vue内置的,直接用这个组件标签就可以
<template>
<div>
<!-- 通过点击按钮让p标签出现或者消失,也就是vue文档说的插入(进入)或删除(离开) -->
<button @click="show = !show">切换</button>
<!-- 这个是transition组件标签 -->
<transition>
<!-- 单标签/一个标签,你也可以把单标签换成单组件,原理是一样的 -->
<p v-if="show">hello</p>
</transition>
</div>
</template>
<script>
export default {
name:'Item',
data() {
return {show: false}
},
}
</script>
<style>
/* 在p标签插入dom之前vue自动添加.v-enter在p标签身上,这是vue给我们提供的类名 */
.v-enter{
/* 比如我让p标签在插入之前向左移动100px */
margin-left: 100px;
}
/* 在p标签插入dom之后vue自动添加.v-enter-to在p标签身上,这是vue给我们提供的类名 */
.v-enter-to{
margin-left: 0px;
}
</style>
效果如下,文字一闪而过
解释一下上面的例子
下面这段代码,此时的p标签还没插入到Dom中,在插入之前vue自动添加.v-enter的代码让p标签在100px处,因为标签还没插入,所以此时的p标签看不到
.v-enter{
margin-left: 100px;
}
我截了个图,这就是p标签被插入到dom中了
此时下面这段代码被vue自动添加到p标签,也就是说当标签一插入Dom中vue就会添加这段代码在p标签上,所以你就看到p标签一闪而过,从100px到0px
.v-enter-to{
margin-left: 0;
}
如果我们想看到100px到0px之间的移动,那么我们就要用到css的transition属性
在上面例子中加入下面代码
在p标签中加入一个css transition属性
/*这是新加入的 */
p{
transition: all 5s;
}
此时的效果
在100px到0px过渡期间vue也给我们提供了一个css类名.v-enter-active,所以你可以用.v-enter-active代替p
/*代替p标签名,效果一样*/
.v-enter-active{
transition: all 5s;
}
还有一点需要注意:
当我把上面例子中css代码改成这样
.v-enter{
margin-left: 100px;
}
.v-enter-to{
/*从0px改成50px*/
margin-left: 50px;
}
.v-enter-active{
transition: all 5s;
}
效果是这样的
可能你有些疑惑
其实是vue在移除类名时造成的,vue在给标签添加或移除类名时,过程是这样的:
- 1.当p标签在插入前,.v-enter类名被添加到p标签中,但是此时的p标签我们看不到
- 2.当p标签被插入时,.v-enter-to和.v-enter-active同时添加到p标签中,同时.v-entrer类名被移除
- 3.当
transition: all 5s;
的时间(也就是这5秒过渡)走完之后,.venter-to和.v-enter-active这两个类名也会被移除,所以此时的p标签是没有任何css的作用的,所以p标签恢复了原位。
这个是标签的动态图片
当p标签消失时,如果你也需要过渡动画的话,vue也给我们提供了三个css类分别是:
在上面例子中再加入这些代码
.v-leave-active{
transition: all 5s;
}
.v-leave{
margin-left: 100px;
}
.v-leave-to{
margin-left: 50px;
}
.v-leave-active
官方文档:在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。
.v-leave
官方文档:在离开过渡被触发时立刻生效,下一帧被移除。
.v-leave-active和.v-leave是同时被添加到标签中的,但是.v-leave被添加的时间只有一帧
.v-leave-to
官方文档:在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
.v-leave-to是最后一个添加到标签中的
还有一点你要知道当你点击按钮时数据已经更新了,但是标签还没被删除,还在dom中,它要等到过渡结束才会被删除。
让我们先看一下效果:
红线为50px处,也就是p标签从原始位置移动了50px,那么这个.v-leave类好像并没有什么作用,我也确实找不出这个.v-leave类有什么作用
可以为<transition
>添加名字,作用是你可以使用多个<transition>
组件标签
如果你使用一个没有名字的 <transition>
,则 v- 是这些类名的默认前缀。如果你使用了 <transition name="my">
,那么 v-enter 会替换为 my-enter。
CSS 动画(animation属性)
官方文档:CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。
当你使用animation属性时,就没有必要使用 .v-enter / .v-enter-to /.v-leave / .v-leave-to
了
/*使用以下两个即可*/
.v-enter-active {
animation: bounce-in .5s;
}
.v-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
from {
transform: scale(0);
}
to {
transform: scale(1);
}
}
如果你使用transition属性达不到你想要的效果,那你就用animation属性,animation比transition好用多了
比如上面那个例子 ,我是想让p标签离开时先在100px处过渡到50px处,用transition根本达不到这个效果,而用animation就能达到这个效果。
对上面例子 的css代码进行更改
/* 离开动画 */
.v-leave-active {
animation: bounce-out 2s;
}
@keyframes bounce-out {
from {
margin-left: 100px;
}
to {
margin-left: 50px;
}
}
/* 进入动画 */
.v-enter-active {
animation: bounce-in 2s;
}
@keyframes bounce-in {
from {
margin-left: 50px;
}
to {
margin-left: 100px;
}
}
效果如下
进入和离开都达到了我想要的效果,如果用transition,离开动画的效果达不到
自定义过渡的类名
我们还可以自定义vue给我们提供的这六个类名
<div>
<button @click="show = !show">切换</button>
<transition
name="组件标签名"
enter-active-class="自定义类名:ok,可用ok代替v-enter-active"
leave-active-class="自定义类名:is,可用is代替v-leave-active"
enter-class=""
enter-to-class=""
leave-class=""
leave-to-class=""
>
<p v-if="show">hello</p>
</transition>
</div>
自定义类名还有一个作用是,我们可以因此结合第三方css动画库一起使用
我下面使用的是animate动画库,因为动画库用的是animation属性的,所以我需要用到的自定义类名只有enter-active-class
和leave-active-class
我使用的是vue2脚手架
同时使用过渡和动画
如果你同时使用transition
和animation
的话,并且它们两设置的时间也不一样,你可以用type属性决定是以transition的时间为准还是以animation的时间为准
<template>
<div>
<button @click="show = !show">切换</button>
<transition type="transition或tanrsform">
<p v-if="show">hello</p>
</transition>
</div>
</template>
<script>
export default {
name: 'ItemTwo',
data() {
return {
show:true
}
},
}
</script>
<style >
@keyframes move {
0% {
transform: translateX(0px);
}
100% {
transform: translateX(100px);
}
}
.v-enter,.v-leave-to{
margin-top: 100px;
}
/*同时使用transition和animation,它们两的时间分别是5秒和1秒
当你设置type="animation"时,那么整个过渡和动画的时间为5秒
当你设置type="transition"时,那么整个过渡和动画的时间为1秒
如果不设置type的话,那么整个过渡和动画的时间为最长时间的那个*/
.v-enter-active,.v-leave-active {
animation: move 5s;
transition: all 1s;
}
</style>
显性的过渡持续时间
你还可以自己设置过渡和动画的时间,那么将以你的时间为准。单位为毫秒。
<transition :duration="1000">...</transition>
你也可以定制进入和移出的持续时间:
<transition :duration="{ enter: 500, leave: 800 }">...</transition>
JavaScript 钩子
js写法很少用,不如css写法,js和css还可以结合使用,当然如果你不想结合使用,设置一下:css="false"
即可
<template>
<div>
<transition
:css="false"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@enter-cancelled="enterCancelled"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
@leave-cancelled="leaveCancelled"
>
<p v-if="show">hello</p>
</transition>
<button @click="show = !show">切换</button>
</div>
</template>
<script>
export default {
name: 'ItemTwo',
data() {
return {show:false}
},
methods: {
// 进入
beforeEnter(el){
//el就是标签对象,可对标签对象进行操作
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
enter(el, done){
el.style.color="green"
//done()代表着完成,不执行这个done函数,那么它就不会执行下一个afterEnter钩子函数
},
afterEnter(el) {
},
//取消过渡执行这个钩子
enterCancelled(el){
},
// 离开钩子函数就不详细写了
beforeLeave(){},
leave(){},
afterLeave(){},
leaveCancelled(){}
},
}
</script>
当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
还可以结合第三方Velocity js动画库一起使用
具体请看文档,目录:vue2文档->过渡 & 动画->进入/离开 & 列表过渡->JavaScript 钩子
初始渲染的过渡
初始渲染就是在页面刚出现或者刷新的时候实现一些过渡效果,而且默认状态肯定不能是隐藏的,否则无法使用初始渲染。
初始渲染执行的是标签插入的过渡
<transition
<!--appear的全写是appear="true",有appear就有初始渲染-->
appear
<!-- 自定义类名,还可以结合第三库使用使用-->
appear-class=""
appear-to-class=""
appear-active-class=""
>
</transition>
初始渲染还有自定义 JavaScript 钩子,省略了,想看可以去vue2文档查看
多个元素的过渡
有多个元素,然后经过判断只有一个元素存在的情况
<template>
<div>
<transition>
<h1 v-if="show">hello</h1>
<p v-else>hi</p>
</transition>
<button @click="show = !show">切换</button>
</div>
</template>
<script>
export default {
name: 'Item',
data() {
return {show:true}
},
}
</script>
<style >
.v-enter,.v-leave-to{
margin-left: 100px;
}
.v-enter-active,.v-leave-active {
transition: all 3s;
}
</style>
效果如下
如果把h1标签改成p标签,那么两个标签就相同了都是p标签,那么效果就又不一样了
<transition >
<p v-if="show">hello</p>
<p v-else>hi</p>
</transition>
效果如下
这两个标签甚至没有了过渡效果了,这是因为vue为了效率,相同标签不进行切换,只使用一个标签,只替换标签里面的内容,所以相同标签的话,就不存在标签重新插入和删除了。
解决方法:只需在标签中加入key即可
<transition >
<p v-if="show" :key="1">hello</p>
<p v-else :key="2">hi</p>
</transition>
效果恢复了
只有一个标签也是可以使用key的,但是好像没有必要
过渡模式
还有一个问题就是,当我点击切换按钮的时候,这里两个标签的进入和离开的过渡是同时开始的(上面那张图片就是这个效果),如果我不想要这种效果呢?我想进入的标签先开始过渡或者相反效果,也是可以的,vue给我们提供了这两个属性in-out
out-in
可以达成这种效果
下面代码只是对上面“多个元素的过渡”的例子代码中加入mode="in-out或out-in"
<div>
<transition mode="in-out或out-in">
<p v-if="show" :key="1">hello</p>
<p v-else :key="2">hi</p>
</transition>
<button @click="show=!show" class="ok">切换</button>
</div>
这是in-out
的效果
新进来的标签先开始过渡,过渡完成之后,旧的标签才开始过渡
这是out-in
的效果
旧的标签先开始过渡,过渡完成之后,新的标签才开始过渡
多个组件的过渡
多个组件过渡就是多个组件中只能显示一个组件,只需要使用<component>
动态组件来完成即可,如需了解动态组件请点击
<transition>
<component :is="view"></component>
</transition>
列表过渡
列表过渡就是这个组件<transition-group>
,如果你需要多个标签有过度效果就用它,它有几个特点:
- 1.它和
<transition>
(也叫单标签或单组件过渡)不同的是<transition>
不会包裹一个父标签,而<transition-group>
则会包裹一个父标签,默认是<span>
,但是可以通过tag属性来更改为其他标签,比如:<transition-group> tag="p"
这是<transition>
:
<transition>
<span>hello</span>
</transition>
这是<transition-group>
:
<!--<transition-group>和<transition>一样也是可以使用name属性来命名的,我就不不用了-->
<!--不设置tag,默认span标签-->
<transition-group tag="p">
<!--在标签中必须写这个key值-->
<span v-for="item in items" :key="item" > {{ item }} </span>
</transition-group>
//js中
data() {
return {
items: [1,2],
}
包裹了一个p标签
- 2.过渡模式
out-in/in-out
不可用,因为我们不再相互切换特有的元素 - 3.内部元素总是需要提供唯一的 key值。
- 4.拿上面最近那张图片做比例 ,
v-enter/v-leave
等等这些会添加在span标签中,而不是p标签中。官方文档:CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
列表的进入/离开过渡、列表的排序过渡
我们先来看一个用<transition-group>
来做随机添加/删除列表数字的例子
<template>
<div>
<button @click="add">增加</button>
<button @click="remove">删除</button>
<transition-group tag="p">
<span v-for="item in items" :key="item" >{{ item }}</span>
</transition-group>
</div>
</template>
<script>
export default {
name:"Item",
data() {
return {
items: [1,2,3,4,5,6,7,8,9],
nextNum: 10
}
},
methods: {
add(){
//随机数
let nub = Math.floor(Math.random() * this.items.length)
this.items.splice(nub, 0,this.nextNum++)
},
remove(){
// 随机数
let nub = Math.floor(Math.random() * this.items.length)
this.items.splice(nub, 1)
}
},
}
</script>
<style>
span{
display: inline-block;
}
.v-enter,.v-leave-to{
transform: translateY(30px);
}
.v-enter-active, .v-leave-active{
transition: all 1s;
}
</style>
这里的span为什么设置为行内块标签呢?
是因为我设置的过渡效果是transform,transform对行内标签无作用,只对行内块/块级标签有作用
如果我设置的过渡效果是animation(animation对行内标签是否有作用,取决于你在声明@kayfranes时里面用什么属性)或其他的属性,那么对行内标签是有作用的,那就不用把行内标签变成块级或者行内块
效果如下:
这个例子有个问题,当添加和移除标签的时候,周围的标签会瞬间移动到他们的新布局的位置,而不是平滑的过渡。
想要周围的标签也能够有平滑的过渡,就要使用到.v-move
类名,它会在标签位置改变的过程中添加
对上面例子的css代码中加入一行代码即可
/*如果你的<transition-group name="flip">有名字,那么你的.v-move类名,得这样写.flip-move*/
.v-move{
transition: all 1s;
}
效果如下:
当周围标签位置改变时,.v-move
就会添加在位置改变的标签上,当标签过渡完之后位置改变的标签上的.v-move
又被移除
但是这个例子还有一个问题,就是删除的时候,周围的标签没有过渡的效果,如果你的标签没有涉及到删除,单单使用这.v-move没有任何问题,不用再另外添加代码了,如果涉及到删除,那么就得另外添加一行代码了,看下面的例子。
这是vue文档的例子,不涉及删除元素,使用.v-move
让标签都有过渡
再对上面例子的css代码更改
span{
display: inline-block;
}
.v-enter,.v-leave-to{
transform: translateY(30px);
}
.v-enter-active, .v-leave-active{
transition: all 1s;
}
/*这是新添加的一行代码*/
.v-leave-active{
position: absolute;
}
.v-move{
transition: all 1s;
}
效果如下
而.v-leave-active类中的position: absolute;
,这又是什么作用呢
我们可以先把position: absolute;
注释掉看看效果
有position: absolute;
代码的图片,删除时文字下滑和周围标签移动是同时开始的。
而把position: absolute;
注释掉的这张图片,删除时文字下滑完成之后周围的标签才开始移动到它们的位置上,没有过渡效果。
这是因为v-move
的类只会在周围标签位置有改变的时候添加,删除的标签会占位过渡,过渡完之后再被删除,会导致过渡时周围的标签位置没有改变。过渡结束之后,周围的标签位置再有改变vue也不会给它们添加v-move
了,所以添加position: absolute;
的作用就是让删除标签脱离标准流,此时周围的标签位置就会立刻发生改变,vue就会给它们添加v-move
类,而删除的标签会脱离标准流来进行过渡。这就是我们看到有position: absolute;
代码的那张图片,文字下滑和周围标签移动是同时开始的原因。
使用v-move时还需要注意:想要周围的标签有过渡效果,标签不能是行内标签,只有块级标签和行内块标签才有过渡效果。这是因为vue底层实现用的是transform来实现移动的。
vue文档说v-move
的原理,是基于flip思想实现的,而flip思想是非常推荐使用transform来移动标签的,这是flip官网的图片。还有列表过渡插入元素时用的也是flip思想,总之使用列表过渡时不要用行内元素就行了。
flip思想并不复杂
flip官网点击这里flip
这是我对flip的理解,请点击
还有一个博主对flip的概述也写的很好点这里
当你看到周围标签有平滑过渡时,你看到的并不是真实的标签在移动,而是克隆标签在移动
列表的交错过渡:这个不讲
可复用的过渡、动态过渡
这两个也不讲,感兴趣的可以去vue文档查看
状态过渡
我上面讲的所有效果都是基于标签的,而标签里面的内容也就是数据,数据的动画效果vue并没有提供内置的组件,vue文档说可以结合第三方库来实现数据的动画效果。vue把数据的动画效果叫做状态过渡。
数据的动态效果
vue文档提到的库有:greensock
更多推荐
所有评论(0)