动画技巧 {#animation-techniques}

Vue 提供了 <Transition><TransitionGroup> 组件来处理进入、离开和列表的过渡。然而,在网页上制作动画的方式非常多,即使是在一个 Vue 应用中也是如此。这里我们会探讨一些别的技巧。

基于 CSS class 的动画 {#class-based-animations}

对于那些不是正在进入或离开 DOM 的元素,我们可以通过给它们动态添加 CSS class 来触发动画:

js const disabled = ref(false) function warnDisabled() { disabled.value = true setTimeout(() => { disabled.value = false }, 1500) }
js export default { data() { return { disabled: false } }, methods: { warnDisabled() { this.disabled = true setTimeout(() => { this.disabled = false }, 1500) } } }
  1. <div :class="{ shake: notActivated }">
  2. <button @click="warnDisabled">Click me</button>
  3. <span v-if="disabled">This feature is disabled!</span>
  4. </div>
  1. .shake {
  2. animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
  3. transform: translate3d(0, 0, 0);
  4. }
  5. @keyframes shake {
  6. 10%,
  7. 90% {
  8. transform: translate3d(-1px, 0, 0);
  9. }
  10. 20%,
  11. 80% {
  12. transform: translate3d(2px, 0, 0);
  13. }
  14. 30%,
  15. 50%,
  16. 70% {
  17. transform: translate3d(-4px, 0, 0);
  18. }
  19. 40%,
  20. 60% {
  21. transform: translate3d(4px, 0, 0);
  22. }
  23. }

状态驱动的动画 {#state-driven-animations}

有些过渡效果可以通过动态地插值来实现,例如,在交互时动态地绑定样式到元素,以这个例子为例:

js const x = ref(0) function onMousemove(e) { x.value = e.clientX }
js export default { data() { return { x: 0 } }, methods: { onMousemove(e) { this.x = e.clientX } } }
  1. <div
  2. @mousemove="onMousemove"
  3. :style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }"
  4. class="movearea"
  5. >
  6. <p>Move your mouse across this div...</p>
  7. <p>x: {{ x }}</p>
  8. </div>
  1. .movearea {
  2. transition: 0.3s background-color ease;
  3. }

除了颜色外,你还可以使用样式绑定动画转换、宽度或高度。你甚至可以通过运用弹簧物理学为 SVG 添加动画,毕竟它们也只是 attribute 的数据绑定:

带侦听器的动画 {#animating-with-watchers}

在一些动画创意里,我们可以根据一些数字状态,使用侦听器将任何东西做成动画。例如,我们可以将数字本身变成动画:

js import { ref, reactive, watch } from 'vue' import gsap from 'gsap' const number = ref(0) const tweened = reactive({ number: 0 }) watch(number, (n) => { gsap.to(tweened, { duration: 0.5, number: Number(n) || 0 }) })
js import gsap from 'gsap' export default { data() { return { number: 0, tweened: 0 } }, watch: { number(n) { gsap.to(this, { duration: 0.5, tweened: Number(n) || 0 }) } } }
  1. Type a number: <input v-model.number="number" />
  2. <p>{{ tweened.number.toFixed(0) }}</p>