准备一个演示组件
新建 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>
|