准备一个演示组件

新建 card.css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
.page {
padding: 32px;
margin: 32px;
}
.emoji {
font-size: 80px;
}
.card {

display: flex;
flex-direction: column;
align-items: center;
max-width: 300px;
box-sizing: border-box;
padding: 32px;
margin: 0 auto;
background: f8f8f8;
border-radius: 10px;
}
.card__header {
text-align: center;
margin-bottom: 32px;
}
.card-title {
margin-bottom: 8px;
}
.card-subtitle {
font-size: 12px;
color: #989898;
}
.card__content {
min-height: 250px;
}
.card__action > button {
outline: none;
border: none;
background: none;
border: 2px solid #000000;
padding: 10px 24px;
margin: 4px;
cursor: pointer;
}
.card__action > button:active {
opacity: 0.8;
}

app.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template>
<div class="page">
<div class="card">
<div class="card__header">
<h3 class="card-title">{{ name }}</h3>
<div class="card-subtitle">Transition & Animation</div>
</div>
<div class="card__content">
<div class="emoji">📚</div>
</div>
<div class="card__action">
<button>请按这里</button>
</div>
</div>
</div>
</template>

<script>
export default {
data() {
return {
name: 'nihao~',
};
},
};
</script>

<style>
@import './styles/app.css';
@import './styles/card.css';
</style>

基于 class 的过渡

点击按钮让元素显示隐藏,card.css

1
2
3
4
5
6
7
8
.emoji {
font-size: 80px;
transition: 0.5s;
}
.hidden {
opacity: 0;
transform: translateX(30px);
}

app.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<div class="page">
<div class="card">
<div class="card__header">
<h3 class="card-title">{{ name }}</h3>
<div class="card-subtitle">Transition & Animation</div>
</div>
<div class="card__content">
<div :class="['emoji', { hidden: !isActive }]">📚</div> //绑定class
</div>
<div class="card__action">
<button @click="isActive = !isActive">请按这里</button> //绑定事件
</div>
</div>
</div>
</template>

<script>
export default {
data() {
return {
name: 'nihao~',
isActive: true, //添加属性
};
},
};
</script>

<style>
@import './styles/app.css';
@import './styles/card.css';
</style>

基于 class 的动画

app.vue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<template>
<div class="page">
<div class="card">
<div class="card__header">
<h3 class="card-title">{{ name }}</h3>
<div class="card-subtitle">Transition & Animation</div>
</div>
<div class="card__content">
<div :class="['emoji', { pulse: !isActive }]">😃</div> //绑定类
</div>
<div class="card__action">
<button @click="isActive = !isActive" :class="{ active: isActive }"> //绑定类
请按这里
</button>
</div>
</div>

<div class="status">
<small>isActive:{{ isActive }}</small>
</div>
</div>
</template>

<script>
export default {
data() {
return {
name: 'nihao~',
isActive: false,
};
},
};
</script>

<style>
@import './styles/app.css';
@import './styles/card.css';
</style>

card.css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.status {
text-align: center;
margin: 24px;
}
.pulse {
animation-name: pulse;
animation-duration: 1s;
animation-iteration-count: infinite;
}
@keyframes pulse {
from {
transform: scale3d(1, 1, 1);
}
50% {
transform: scale3d(1.5, 1.5, 1.5);
}
to {
transform: scale3d(1, 1, 1);
}
}

点击按钮后图片开始动画。

transition 进入与离开过渡

在 vue 里,v-if 的上面不能直接使用基于 class 的过渡效果,需要借助 vue 提供的 transition 这个组件,这个组件会自动给标签加上特定的 class,然后去定义这些 class 的样式即可。

1
2
3
<transition>
<div v-if="isActive" class="emoji">😃</div>
</transition>

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.v-enter-from {
opacity: 0;
}
.v-enter-active {
transition: 0.3s;
}
.v-enter-to {
opacity: 1;
}

.v-leave-from {
opacity: 1;
}
.v-leave-active {
transition: 0.3s;
}
.v-leave-to {
opacity: 0;
}

指定过渡效果的名字

使用 name 属性后,会自动加上这个 name 为前缀的 class。

1
2
3
<transition name="slide">
<div v-if="isActive" class="emoji">😃</div>
</transition>

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.slide-enter-from {
opacity: 0;
transform: translateX(30px);
}
.slide-enter-active {
transition: 0.3s;
}
.slide-enter-to {
opacity: 1;
}
.slide-leave-from {
opacity: 1;
}
.slide-leave-active {
transition: 0.3s;
}
.slide-leave-to {
opacity: 0;
transform: translateX(30px);
}

进入与离开动画

1
2
3
<transition name="pulse">
<div v-if="isActive" class="emoji">😃</div>
</transition>

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@keyframes pulse {
from {
transform: scale3d(1, 1, 1);
}
50% {
transform: scale3d(1.5, 1.5, 1.5);
}
to {
transform: scale3d(1, 1, 1);
}
}

.pulse-enter-active {
animation: pulse 1s;
}

.pulse-leave-active {
animation: pulse 1s;
}

自定义过渡类

自定义过渡类可以让我们使用第三方的 css 库来完成动画或过渡。比如 animate.css,引入 css,然后在标签上定义进入和离开的类。具体使用方法可以看 animate 官网。


组件之间的过渡

新建两个组件:ghost-emoji.vue 和 robot-emoji.vue。
ghost-emoji.vue:

1
2
3
<template>
<div class="emoji">👻</div>
</template>

robot-emoji.vue:

1
2
3
<template>
<div class="emoji">🤖</div>
</template>

app.vue 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<template>
<div class="page">
<div class="card">
<div class="card__header">
<h3 class="card-title">{{ name }}</h3>
<div class="card-subtitle">Transition & Animation</div>
</div>
<div class="card__content">
<transition name="pulse" mode="out-in"> //使用out-in ,避免两个组件同时显示
<!-- <div v-if="isActive" class="emoji">😃</div> -->

<component :is="currentEmoji"></component> //使用刚才定义的组件并定义当前显示的组件
</transition>
</div>
<div class="card__action">
<button @click="isActive = !isActive" :class="{ active: isActive }">
请按这里
</button>
</div>
</div>

<div class="status">
<small>isActive:{{ isActive }}</small>
</div>
</div>
</template>

<script>
import GhostEmoji from './components/ghost-emoji'; //引入
import RobotEmoji from './components/robot-emoji'; //引入
export default {
data() {
return {
name: 'nihao~',
isActive: true,
emoji: 'GhostEmoji',
};
},
computed: {
currentEmoji() {
return this.isActive ? 'GhostEmoji' : 'RobotEmoji'; //设置当前显示组件
},
},
components: { //使用组件
GhostEmoji,
RobotEmoji,
},
};
</script>

<style>
@import './styles/app.css';
@import './styles/card.css';
</style>

列表的过渡与动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<template>
<div class="page">
<div class="card">
<div class="card__header">
<h3 class="card-title">{{ name }}</h3>
<div class="card-subtitle">Transition & Animation</div>
</div>
<div class="card__content">
<transition-group name="slide"> //使用transition-group
<div class="emoji" v-for="emoji in emojiList" :key="emoji">
{{ emoji }}
</div>
</transition-group>
</div>
<div class="card__action">
<button @click="shuffle" :class="{ active: isActive }"> //点击使用shuffle方法
请按这里
</button>
<button @click="pop">
请按这里
</button>
</div>
</div>

<div class="status">
<small>isActive:{{ isActive }}</small>
</div>
</div>
</template>

<script>
import _ from 'lodash';
export default {
data() {
return {
name: 'nihao~',
isActive: true,
emojiList: ['📚', '🌵', '🤖', '🍃'], //创建列表
};
},
computed: {
currentEmoji() {
return this.isActive ? 'GhostEmoji' : 'RobotEmoji';
},
},
methods: {
shuffle() {
this.emojiList = _.shuffle(this.emojiList); //lodash里的shuffle方法可以打乱数组的顺序
},
pop() {
this.emojiList.pop(); //删除数组的一项
},
},
};
</script>

<style>
@import './styles/app.css';
@import './styles/card.css';
</style>