完整原文地址见简书https://www.jianshu.com/p/f3b52299aaa6
本文内容提要
Vue常规动画写法
Vue过渡动画 常规写法与 例程
上例的另一种实现方式
入场动画
出场动画
出入场动画同时实现时,可以简化以上代码
出场入场帧动画
使用
name=
对动画进行 片段式地 命名对动画类的完全命名
完全命名的方式 使得 容易接入 第三方库
注意以上案例,将
v-if
换成v-show
也是可以正常运行的颜色过渡和位移 动画 结合
控制组合动画时长 以某一类型动画的时间为准
控制组合动画时长 以自定义的时长为准
分别 统一 出入场动画的时延
禁用CSS动画,使用JS动画
最基本的 多个 单元素标签 切换案例
带上入场 退场 动画的 两个单元素标签切换
带上入场 退场 动画的 两个组件 的切换
<component>
组件占位 + is属性 + 双向绑定特性 实现上例效果列表动画
状态动画
Vue常规动画写法
关键帧 --- CSS类 --- data数据 --- DOM的Class属性
-- 使用@keyframes [关键帧实例名]
配置好关键帧;
-- 使用animation
配置关键帧
以及动画过程到完成
的时延
,
完成动画的定义【写在一个CSS类中(如下的myAnimation
)】;
-- 在data
中定义一个以 上面定义的动画CSS类
实例(如myAnimation
) 为属性值的 数据字段
(如myAnimateData
);
-- 在dom中使用:class=[以 动画CSS类实例 为属性的 数据字段]
,
引用这个数据字段
(myAnimateData
)即可,至此完成动画定义;
-- 数据字段
(如myAnimateData
)中,可以通过对 属性值即动画CSS类
实例的 布尔值的 改变,
去控制动画的开关,如下 配置false 为关:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
@keyframes leftToRight {
0% {
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
0% {
transform: translateX(0px);
}
}
.myAnimation {
animation: leftToRight 3s;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
myAnimateData: {
myAnimation: false
}
}
},
template: `
<div>
<div :class="myAnimateData">heheheda</div>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果,没有动画,DOM中也没显示对应的class:
![](https://i-blog.csdnimg.cn/blog_migrate/c1a7ea4d7be4c74b80511c917e135569.png)
<script>
const app = Vue.createApp({
data() {
return {
myAnimateData: {
myAnimation: true
}
}
},
template: `
<div>
<div :class="myAnimateData">heheheda</div>
</div>`
});
const vm = app.mount('#heheApp');
</script>
运行时产生动画:
![](https://i-blog.csdnimg.cn/blog_migrate/84b266e7b9750c24c0515a8b7942220f.png)
可以配合按钮和点击事件,动态 交互地 开关动画:
<script>
const app = Vue.createApp({
data() {
return {
myAnimateData: {
myAnimation: true
}
}
},
methods: {
handleClick() {
this.myAnimateData.myAnimation = !this.myAnimateData.myAnimation;
}
},
template: `
<div>
<div :class="myAnimateData">heheheda</div>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
Vue过渡动画 常规写法与 例程
-- 使用transition: [时延] background-color ease;
定义 在一个时延内的过渡动画
,background-color
指定过渡对象是背景颜色
,ease
指定为平缓地进行
;
-- 类似上例,在组件的data中,定义一个 对应CSS类的 Object类型数据字段
,并在其中包含过渡动画
和定义好的背景颜色
的数据字段;
-- 在template
中,使用:class=[类实例名]
引用data
中的CSS类实例
即可;
-- 可以准备一个触发事件
,在事件中反转
两个背景颜色值,由此可实现过渡动画:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
.myTransition {
transition: 3s background-color ease;
}
.aquamarine {
background-color: aquamarine;
}
.orange {
background-color: orange;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
myTransitData: {
myTransition: true,
aquamarine: true,
orange: false
}
}
},
methods: {
handleClick() {
this.myTransitData.aquamarine = !this.myTransitData.aquamarine;
this.myTransitData.orange = !this.myTransitData.orange;
}
},
template: `
<div>
<div :class="myTransitData">heheheda</div>
<button @click="handleClick">使用transition切换背景色</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果:
![](https://i-blog.csdnimg.cn/blog_migrate/8a33e9201480078c074917d342bfa728.png)
![](https://i-blog.csdnimg.cn/blog_migrate/122487c4b0102a2fe174d01d29d1bcba.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1bef3bc64a33edb2d2e810e040269868.png)
上例的另一种实现方式
-- 定义css动画类
,
在dom节点直接使用class=[CSS动画类]
配置上这个CSS动画类;
-- data
中定义初始背景颜色键值
,打包成object
类型,
配置到DOM节点的:style=
上,作双向绑定
;
-- 把css
中定义的背景颜色字段
都去掉,
直接写在触发事件
的方法中,在其中通过更改绑定的style字段的值
改变背景颜色;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
.myTransition {
transition: 3s background-color ease;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
styleObj: {
background: "aquamarine"
}
}
},
methods: {
handleClick() {
if (this.styleObj.background === 'aquamarine') {
this.styleObj.background = 'orange';
} else {
this.styleObj.background = 'aquamarine';
}
}
},
template: `
<div>
<div class="myTransition" :style="styleObj" >heheheda</div>
<button @click="handleClick">使用transition切换背景色</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果如上例;
入场动画
如下,<style>
标签定义的三个类,
分别指定 入场动画
的开始时
的透明度、
过程持续的时延
和 速度
(ease -- 缓慢)、
入场动画的结束时
的透明度;template
中,
使用<transition>
标签对 包裹 要实现入场动画
的DOM节点即可;
<head>
...
<style>
.v-enter-from{
opacity: 0;
}
.v-enter-active {
transition: opacity 3s ease;
}
.v-enter-to {
opacity: 1;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition>
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果,实现入场动画:
初始:
![](https://i-blog.csdnimg.cn/blog_migrate/2f30c5ba943cb5aeb61fbc6d31a1fa0d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d265764f849524117d2cbb984e547549.png)
![](https://i-blog.csdnimg.cn/blog_migrate/7a465fd9fd4eb4c1c8b41e7b1f91f20c.png)
出场动画
理同入场动画,其中,v-leave-from
表示 出场动画
的开始时
的透明度、v-leave-active
表示过程持续的时延
和 速度
(ease -- 缓慢)、v-leave-to
表示出场动画的结束时
的透明度;
其余步骤 同入场动画:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
.v-enter-from{
opacity: 0;
}
.v-enter-active {
transition: opacity 3s ease-out;
}
.v-enter-to {
opacity: 1;
}
.v-leave-from {
opacity: 1;
}
.v-leave-active {
transition: opacity 3s ease-in;
}
.v-leave-to {
opacity: 0;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition>
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果:
初始:
![](https://i-blog.csdnimg.cn/blog_migrate/c45642404431eb683b09c70271eb130b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e603dba1a1302f240090a5320095b4ba.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b3d7d975e6b47e56eeeb37836138fd5f.png)
出入场动画同时实现时,可以简化以上代码
两个v-xxx-active
可以写到一起,
如果v-leave-from
指定的值与v-enter-to
相同(一般都是相同的),那也可以省略它;
以下代码实现的效果,同上:
...
<style>
.v-enter-from{
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: opacity 3s ease-out;
}
.v-enter-to {
opacity: 1;
}
.v-leave-to {
opacity: 0;
}
</style>
...
出场入场帧动画
准备好一个keyframes
,然后把它写在v-xxx-active
中即可:
···
<style>
@keyframes shake {
0% {
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
.v-enter-active {
animation: shake 2s;
}
.v-leave-active {
animation: shake 2s;
}
</style>
···
使用name=
对动画进行 片段式地 命名
可以在template
中,
在<transition>
标签中,用name=
指定一个命名,
然后在style中定义css类时,
将之前的v-xxx-xxx
等定义符换成[命名]-xxx-xxx
即可:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
@keyframes shake {
0% {
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
.heheda-enter-active {
animation: shake 2s;
}
.heheda-leave-active {
animation: shake 2s;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition name="heheda">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
对动画类的完全命名
即直接在template
中,在<transition>
标签中,
使用[原css命名] = [新命名]
的方式,对整个CSS类取别名,
用的时候,直接使用新命名即可:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
@keyframes shake {
0% {
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
.hihi {
animation: shake 2s;
}
.byebye {
animation: shake 2s;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition
enter-active-class="hihi"
leave-active-class="byebye">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
关键代码:
<!DOCTYPE html>
<html lang="en">
<head>
...
<style>
...
.hihi {
animation: shake 2s;
}
.byebye {
animation: shake 2s;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
...
<script>
...
template: `
...
<transition
enter-active-class="hihi"
leave-active-class="byebye">
<div v-if="show">heheda</div>
</transition>
...
</script>
运行效果同上例;
完全命名的方式 使得 容易接入 第三方库
这里以引入Animate.css
为例;
官网:https://animate.style/
官网首页如下,右侧列表是各种动画类型,点击可以预览效果:
![](https://i-blog.csdnimg.cn/blog_migrate/afb7709087ad6ed31061a44da91e11b8.png)
官网简略引导:
(如下可知,即
框架
已经把动画
定义实现
好了,使用时只用直接使用
定义好的框架
的样式命名
即可)
![](https://i-blog.csdnimg.cn/blog_migrate/83b9337ce6ba85ed8200724de208e5f2.png)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<script src="https://unpkg.com/vue@next"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition
enter-active-class="animate__animated animate__bounce"
leave-active-class="animate__animated animate__bounce">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
闪烁效果:
template: `
<div>
<transition
enter-active-class="animate__animated animate__flash"
leave-active-class="animate__animated animate__flash">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
注意以上案例,将v-if
换成v-show
也是可以正常运行的
区别在于隐藏组件的底层机制不同而已,
在博客笔记《Vue3 | 条件渲染 与 列表循环渲染》我们讨论过这个事情;
颜色过渡和位移 动画 结合
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
@keyframes shake {
0% {
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
.v-enter-from {
color: red;
}
.v-enter-active {
animation: shake 2s;
transition: all 2s ease-in;
}
.v-leave-active {
color: red;
animation: shake 2s;
transition: all 2s ease-in;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition>
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
关键代码:
入场,从红色开始,到黑色(默认颜色);
出场,从黑色(默认颜色)开始,到红色;all
表示过渡特性
适配到 所用类型的动画;
.v-enter-from {
color: red;
}
.v-enter-active {
animation: shake 2s;
transition: all 2s ease-in;
}
.v-leave-active {
color: red;
animation: shake 2s;
transition: all 2s ease-in;
}
控制组合动画时长 以某一类型动画的时间为准
在<transition>
标签上,
写上type="transition"
,则组合动画的时长 以过渡动画 为准;
写上type="animation
,则组合动画的时长 以普通类型动画 为准;
如下案例,写上type="transition"
,
则组合动画在 过渡动画执行完毕(即3s)之后,
会立即停止 正在运行的 所有动画:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
@keyframes shake {
0% {
transform: translateX(-100px);
}
50% {
transform: translateX(-50px);
}
100% {
transform: translateX(50px);
}
}
.v-enter-from {
color: red;
}
.v-enter-active {
animation: shake 6s;
transition: all 3s ease-in;
}
.v-leave-active {
color: red;
animation: shake 6s;
transition: all 3s ease-in;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
}
},
template: `
<div>
<transition type="transition">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
控制组合动画时长 以自定义的时长为准
在<transition>
标签上,
写上:duration="[动画时长 / ms]"
,则组合动画的时长 以这里定义的数据 为准,
无论CSS类中,定义了多长的时延:
template: `
<div>
<transition :duration="1000">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
分别 统一 出入场动画的时延
:duration="[{enter: [入场动画时延], leave:[出场动画时延]}]"
template: `
<div>
<transition :duration="{enter: 1000, leave: 3000}">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
禁用CSS动画,使用JS动画
-- 使用:css="false"
禁用CSS动画,使得CSS动画都失效(如果有定义的话);
-- @before-enter = "[方法名]"
定义 入场就绪
及 开始前
状态的动画回调方法;
-- @enter = "[方法名]"
定义 动画运行时
状态的 回调方法;
-- @after-enter="[方法名]"
定义 动画结束时
状态的 回调方法;
-- done();
通知架构动画已经结束,可以回调 handleEnterEnd(el)
了;
【注意,以上是入场动画
的钩子回调,
把enter
换成leave
,即是对应的退场动画
的钩子回调】
如下代码,handleBeforeEnter(el)
指定 初始动画颜色 为 橙色;handleEnterActive(el, done)
使得 动画在 橙色 与 蓝色之间 动态切换,
配合 setInterval(() => {}, 1000)
时隔一秒切换一次;clearInterval(animation);
配合 setTimeout(() => {}, 5000)
使得5秒后关闭动画;
随后调用done();
通知架构 动画已经结束,可以回调 handleEnterEnd(el)
了;handleEnterEnd(el)
调试性地 弹出一个弹窗;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
},
handleBeforeEnter(el) {
el.style.color = "orange";
},
handleEnterActive(el, done) {
const animation = setInterval(() => {
const color = el.style.color;
if(color === "orange") {
el.style.color = 'blue';
} else {
el.style.color = 'orange';
}
}, 1000)
setTimeout(() => {
clearInterval(animation);
done();
}, 5000)
},
handleEnterEnd(el) {
alert("动画结束!!!");
}
},
template: `
<div>
<transition
:css="false"
@before-enter = "handleBeforeEnter"
@enter="handleEnterActive"
@after-enter="handleEnterEnd">
<div v-if="show">heheda</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
![](https://i-blog.csdnimg.cn/blog_migrate/52c9f96d5e599e50b6ba12405d5a5ed0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/66e4dccdc34137e2e565ed242e3dada4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4a52e85e3d809735a5e9fd003982d0a0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/bb7e2fb55e14276e1aceaa760abafebf.png)
最基本的 多个 单元素标签 切换案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
},
},
template: `
<div>
<transition >
<div v-if="show">heheda</div>
<div v-else="show">lueluelue</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
带上入场 退场 动画的 两个单元素标签切换
-- css块上面已经讲过了,这里主要是看mode="in-out"
;
这里指定为mode="in-out"
的话,
则切换时 先进行入场节点的 入场 及其 动画【in】,
再进行退场节点 的 入场 及其 动画【out】;
【缺点:入场 与 退场的节点,在入场动画完毕前,会同框】
-- 如 指定为mode="out-in"
,则顺序与上相反;
【特性:入场 与 退场的节点 不会同框】
-- appear
特性:初始加载节点的时候,就会启动入场动画
,
没有加这个标签,入场动画
需要触发才会启动;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
.v-leave-to {
opacity: 0;
}
.v-enter-from {
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: opacity 2s ease-in;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
},
},
template: `
<div>
<transition mode="out-in" appear>
<div v-if="show">heheda</div>
<div v-else="show">lueluelue</div>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
带上入场 退场 动画的 两个组件 的切换
基于上例进行小改动即可,其原理是类似的,
以下代码实现的效果 同上例;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
.v-leave-to {
opacity: 0;
}
.v-enter-from {
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: opacity 2s ease-in;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const ComponentA = {
template: `<div>heheda</div>`
}
const ComponentB = {
template: `<div>lueluelue</div>`
}
const app = Vue.createApp({
data() {
return {
show: false
}
},
methods: {
handleClick() {
this.show = !this.show;
},
},
components: {
'component-a': ComponentA,
'component-b': ComponentB,
},
template: `
<div>
<transition mode="out-in" appear>
<component-a v-if="show"/>
<component-b v-else="show"/>
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
<component>
组件占位 + is属性 + 双向绑定特性 实现上例效果
-- data
字段 存储要展示的子组件 的 组件名;
-- 点击事件中 更改data
字段 以 更换 展示的子组件,
同时产生组件的 入场退场
,触发相关动画;
-- template
中 使用 <component>
标签占位,
使用is
控制要展示的组件, 指定值为 data
字段;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
.v-leave-to {
opacity: 0;
}
.v-enter-from {
opacity: 0;
}
.v-enter-active,
.v-leave-active {
transition: opacity 2s ease-in;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const ComponentA = {
template: `<div>heheda</div>`
}
const ComponentB = {
template: `<div>lueluelue</div>`
}
const app = Vue.createApp({
data() {
return {
component : 'component-a'
}
},
methods: {
handleClick() {
if (this.component === 'component-a') {
this.component = 'component-b';
} else {
this.component = 'component-a';
}
},
},
components: {
'component-a': ComponentA,
'component-b': ComponentB,
},
template: `
<div>
<transition mode="out-in" appear>
<component :is="component">
</transition>
<button @click="handleClick">切换</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果同上例;
列表动画
即列表增删元素时,产生的
入场 和 出场动画
;
主要是对itemView
、v-for
等标签套上<transition-group>
这个特殊动画标签,
然后点击事件时使用unshift
在队头添加元素,
其他的定义跟普通动画差不多;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<style>
.v-enter-from {
opacity: 0;
transform: translateY(30px);
}
.v-enter-active {
transition: all .5s ease-in;
}
.v-enter-to {
opacity: 1;
transform: translateY(0);
}
.v-move {
transform: all .5s ease-in;
}
.list-item {
display: inline-block;
margin-right: 10px;
}
</style>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
list : [1, 2, 3]
}
},
methods: {
handleClick() {
this.list.unshift(this.list.length + 1);
},
},
template: `
<div>
<transition-group>
<span
class="list-item"
v-for="item in list"
:key = "item">{{item}}</span>
</transition-group>
<button @click="handleClick">增加</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果:
![](https://i-blog.csdnimg.cn/blog_migrate/09293e1f7506aab99202ddb597be36cf.png)
状态动画
显示一个值【状态】 到 另外一个值【状态】 的变化过程,
类似于Android的ValueAnimator
;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello World! heheheheheheda</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="heheApp"></div>
</body>
<script>
const app = Vue.createApp({
data() {
return {
number: 1,
animateNumber: 1
}
},
methods: {
handleClick() {
this.number = 10;
const animation = setInterval(() => {
this.animateNumber += 1;
if(this.animateNumber >= this.number){
clearInterval(animation);
}
}, 100);
},
},
template: `
<div>
<span>{{animateNumber}}</span>
<button @click="handleClick">改变</button>
</div>`
});
const vm = app.mount('#heheApp');
</script>
</html>
运行效果:
![](https://i-blog.csdnimg.cn/blog_migrate/c368c0d7b583e066a9761f73a5f36fc4.png)