Skip to content

过度动画

类名

  1. v-enter-from:进入动画的起始状态。
  2. v-enter-active:进入动画的生效状态。
  3. v-enter-to:进入动画的结束状态。
  4. v-leave-from:离开动画的起始状态。
  5. v-leave-active:离开动画的生效状态。
  6. v-leave-to:离开动画的结束状态。

class命名规则

我们可以给 <Transition> 组件传一个 name prop 来声明一个过渡效果名:

js
<Transition name="dsj">
  ...
</Transition>

对于一个有名字的过渡效果,对它起作用的过渡 class 会以其名字而不是 v 作为前缀。比如,上方例子中被应用的 class 将会是 dsj-enter-active 而不是 v-enter-active。这个“dsj”过渡的 class 应该是这样:

css
.dsj-enter-active {
  ...
}

CSS 的 transition

原生 css transition

js
import { ref } from 'vue'
const isShow = ref(false)
html
<button @click="isShow = !isShow"> 切换 </button>
<hr>
<transition>
  <h2 class="" v-if="isShow">不忘初心,方得始终.</h2>
</transition>
css
h2 {
  display: inline-block;
}
.v-enter-from,
.v-leave-to {
  opacity: 0;
  transform: scale(.5);
}
.v-enter-to,
.v-leave-from {
  opacity: 1;
  transform: scale(1);
}
.v-enter-active,
.v-leave-active {
  transition: all 2s ease;
}

CSS 的 animation

原生 css animation

js
import { ref } from 'vue'
const isShow = ref(false)
html
<button @click="isShow = !isShow"> 切换 </button>
<hr>
<transition name="dsj">
  <h2 class="" v-if="isShow">不忘初心,方得始终.</h2>
</transition>
css
h2 {
  display: inline-block;
}
.dsj-enter-active {
  animation: dsjEnterAnim 2s ease;
}
.dsj-leave-active {
  animation: dsjLeaveAnim 2s ease;
}
@keyframes dsjEnterAnim {
  0% {
    opacity: 0;
    transform: scale(0);
  }
  50% {
    opacity: .5;
    transform: scale(.5);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}
@keyframes dsjLeaveAnim {
   0% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: .5;
    transform: scale(.5);
  }
  100% {
    opacity: 0;
    transform: scale(0);
  }
}

过渡模式

在之前的例子中,进入和离开的元素都是在同时开始动画的,因此我们不得不将它们设为 position: absolute 以避免二者同时存在时出现的布局问题。

js
<div>
  <button @click="isShow = !isShow">切换</button>
</div>
<transition name="dsj" mode="out-in">
  <h2 v-if="isShow">哈哈哈</h2>
  <h2 v-else>嘻嘻嘻</h2>
</transition>

mode="out-in" 先移除后加入

mode="in-out" 先加入后移除(少)

动态组件的切换

js
import { ref } from 'vue';

import Home from './pages/Home.vue'
import About from './pages/About.vue'

const isShow = ref(false)
html
<div>
  <button @click="isShow = !isShow">切换</button>
</div>
<!-- 首次渲染动画 appear -->
<transition name="dsj" mode="out-in" appear>
  <component :is="isShow ? Home:About"></component>
</transition>

列表动画

js
import { ref } from 'vue';
import { shuffle } from 'underscore'

const nums = ref([1, 2, 3, 4, 5, 6, 7, 8, 9])

const addNumber = () => {
  nums.value.splice(randomIndex(), 0, nums.value.length)
}
const removeNumber = () => {
  nums.value.splice(randomIndex(), 1)
}
const shuffleNumber = () => {
  nums.value = shuffle(nums.value)
}
const randomIndex = () => {
  return Math.floor(Math.random() * nums.value.length)
}
html
<button @click="addNumber">添加数字</button>
<button @click="removeNumber">删除数字</button>
<button @click="shuffleNumber">打乱数字</button>
<hr>
<transition-group tag="div" name="dsj">
  <template v-for="item in nums" :key="item">
    <div class="item">{{ item }}</div>
  </template>
</transition-group>
css
.item {
  display: inline-block;
  margin: 10px;
}
.dsj-enter-from,
.dsj-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
.dsj-enter-to,
.dsj-leave-from {
  opacity: 1;
  transform: translateY(0);
}
.dsj-enter-active,
.dsj-leave-active {
  transition: all 2s ease;
}
/* 移除时不让他占位 */
.dsj-leave-active {
  position: absolute;
}
/* 针对其他移动的阶段需要 */
.dsj-move {
  transition: all 2s ease;
}

v-move 针对其他动画

必须有 key

npm i underscore 打乱数字的 js 库