Vue 3.0 過渡&動(dòng)畫概述

2021-07-16 11:30 更新

Vue 提供了一些抽象概念,可以幫助處理過渡和動(dòng)畫,特別是在響應(yīng)某些變化時(shí)。這些抽象的概念包括:

  • 在 CSS 和 JS 中,使用內(nèi)置的 <transition> 組件來鉤住組件中進(jìn)入和離開 DOM。
  • 過渡模式,以便你在過渡期間編排順序。
  • 在處理多個(gè)元素位置更新時(shí),使用 <transition-group> 組件,通過 FLIP 技術(shù)來提高性能。
  • 使用 watchers 來處理應(yīng)用中不同狀態(tài)的過渡。

我們將在本指南接下來的三個(gè)部分中介紹所有這些以及更多內(nèi)容。然而,除了提供這些有用的 API 之外,值得一提的是,我們前面介紹的 class 和 style 聲明也可以應(yīng)用于動(dòng)畫和過渡,用于更簡單的用例。

在下一節(jié)中,我們將回顧一些 web 動(dòng)畫和過渡的基礎(chǔ)知識(shí),并提供一些資源鏈接以進(jìn)行進(jìn)一步的研究。如果你已經(jīng)熟悉 web 動(dòng)畫,并且了解這些原理如何與 Vue 的某些指令配合使用,可以跳過這一節(jié)。對于希望在開始學(xué)習(xí)之前進(jìn)一步了解網(wǎng)絡(luò)動(dòng)畫基礎(chǔ)知識(shí)的其他人,請繼續(xù)閱讀。

#基于 class 的動(dòng)畫和過渡

盡管 <transition> 組件對于組件的進(jìn)入和離開非常有用,但你也可以通過添加一個(gè)條件 class 來激活動(dòng)畫,而無需掛載組件。

  1. <div id="demo">
  2. Push this button to do something you shouldn't be doing:<br />
  3. <div :class="{ shake: noActivated }">
  4. <button @click="noActivated = true">Click me</button>
  5. <span v-if="noActivated">Oh no!</span>
  6. </div>
  7. </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. backface-visibility: hidden;
  5. perspective: 1000px;
  6. }
  7. @keyframes shake {
  8. 10%,
  9. 90% {
  10. transform: translate3d(-1px, 0, 0);
  11. }
  12. 20%,
  13. 80% {
  14. transform: translate3d(2px, 0, 0);
  15. }
  16. 30%,
  17. 50%,
  18. 70% {
  19. transform: translate3d(-4px, 0, 0);
  20. }
  21. 40%,
  22. 60% {
  23. transform: translate3d(4px, 0, 0);
  24. }
  25. }

  1. const Demo = {
  2. data() {
  3. return {
  4. noActivated: false
  5. }
  6. }
  7. }
  8. Vue.createApp(Demo).mount('#demo')

點(diǎn)擊此處實(shí)現(xiàn)

#過渡與 Style 綁定

一些過渡效果可以通過插值的方式來實(shí)現(xiàn),例如在發(fā)生交互時(shí)將樣式綁定到元素上。以這個(gè)例子為例:

  1. <div id="demo">
  2. <div
  3. @mousemove="xCoordinate"
  4. :style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }"
  5. class="movearea"
  6. >
  7. <h3>Move your mouse across the screen...</h3>
  8. <p>x: {{x}}</p>
  9. </div>
  10. </div>

  1. .movearea {
  2. transition: 0.2s background-color ease;
  3. }

  1. const Demo = {
  2. data() {
  3. return {
  4. x: 0
  5. }
  6. },
  7. methods: {
  8. xCoordinate(e) {
  9. this.x = e.clientX
  10. }
  11. }
  12. }
  13. Vue.createApp(Demo).mount('#demo')

點(diǎn)擊此處實(shí)現(xiàn)

在這個(gè)例子中,我們是通過使用插值來創(chuàng)建動(dòng)畫,將觸發(fā)條件添加到鼠標(biāo)的移動(dòng)過程上。同時(shí)將 CSS 過渡屬性應(yīng)用在元素上,讓元素知道在更新時(shí)要使用什么過渡效果。

#性能

你可能注意到上面顯示的動(dòng)畫使用了 transforms 之類的東西,并應(yīng)用了諸如 perspective 之類的奇怪的 property——為什么它們是這樣實(shí)現(xiàn)的,而不是僅僅使用 margintop 等?

我們可以通過對性能的了解,在 web 上創(chuàng)建極其流暢的動(dòng)畫。我們希望盡可能對元素動(dòng)畫進(jìn)行硬件加速,并使用不觸發(fā)重繪的 property。我們來介紹一下如何實(shí)現(xiàn)這個(gè)目標(biāo)。

#Transform 和 Opacity

我們可以通過工具,例如 CSS Triggers 來查看哪些屬性會(huì)在動(dòng)畫時(shí)觸發(fā)重繪。在工具中,查看 transform 的相關(guān)內(nèi)容,你將看到:

非常好的是,更改 transform 不會(huì)觸發(fā)任何幾何形狀變化或繪制。這意味著該操作可能是由合成器線程在 GPU 的幫助下執(zhí)行。

opacity 屬性的行為也類似。因此,他們是在 web 上做元素移動(dòng)的理想選擇。

#硬件加速

諸如 perspectivebackface-visibilitytransform:translateZ(x) 等 property 將讓瀏覽器知道你需要硬件加速。

如果要對一個(gè)元素進(jìn)行硬件加速,可以應(yīng)用以下任何一個(gè) property (并不是需要全部,任意一個(gè)就可以):

  1. perspective: 1000px;
  2. backface-visibility: hidden;
  3. transform: translateZ(0);

許多像 GreenSock 這樣的 JS 庫都會(huì)默認(rèn)你需要硬件加速,并在默認(rèn)情況下應(yīng)用,所以你不需要手動(dòng)設(shè)置它們。

#Timing

對于簡單 UI 過渡,即從一個(gè)狀態(tài)到另一個(gè)沒有中間狀態(tài)的狀態(tài),通常使用 0.1s 到 0.4s 之間的計(jì)時(shí),大多數(shù)人發(fā)現(xiàn) 0.25s 是一個(gè)最佳選擇。你能用這個(gè)定時(shí)做任何事情嗎?并不是。如果你有一些元素需要移動(dòng)更大的距離,或者有更多的步驟或狀態(tài)變化,0.25s 并不會(huì)有很好的效果,你將不得不有更多的目的性,而且定時(shí)也需要更加獨(dú)特。但這并不意味著你不能在應(yīng)用中重復(fù)使用效果好的默認(rèn)值。

你也可能會(huì)發(fā)現(xiàn),起始動(dòng)畫比結(jié)束動(dòng)畫的時(shí)間稍長一些,看起來會(huì)更好一些。用戶通常是在動(dòng)畫開始時(shí)被引導(dǎo)的,而在動(dòng)畫結(jié)束時(shí)沒有那么多耐心,因?yàn)樗麄兿肜^續(xù)他們的動(dòng)作。

#Easing

Easing 是在動(dòng)畫中表達(dá)深度的一個(gè)重要方式。動(dòng)畫新手最常犯的一個(gè)錯(cuò)誤是在起始動(dòng)畫節(jié)點(diǎn)使用 ease-in,在結(jié)束動(dòng)畫節(jié)點(diǎn)使用 ease-out。實(shí)際上你需要的是反過來的。

如果我們將這些狀態(tài)應(yīng)用于過渡,它應(yīng)該像這樣:

  1. .button {
  2. background: #1b8f5a;
  3. /* 應(yīng)用于初始狀態(tài),因此此轉(zhuǎn)換將應(yīng)用于返回狀態(tài) */
  4. transition: background 0.25s ease-in;
  5. }
  6. .button:hover {
  7. background: #3eaf7c;
  8. /* 應(yīng)用于懸停狀態(tài),因此在觸發(fā)懸停時(shí)將應(yīng)用此過渡 */
  9. transition: background 0.35s ease-out;
  10. }

點(diǎn)擊此處實(shí)現(xiàn)

Easing 也可以表達(dá)動(dòng)畫元素的質(zhì)量。以下面的 Pen 為例,你認(rèn)為哪個(gè)球是硬的,哪個(gè)球是軟的?

點(diǎn)擊此處實(shí)現(xiàn)

你可以通過調(diào)整你的 Easing 來獲得很多獨(dú)特的效果,使你的動(dòng)畫非常時(shí)尚。CSS 允許你通過調(diào)整 cubic bezier 屬性來修改 Easing,Lea Verou 開發(fā)的這個(gè) playground 對探索這個(gè)問題非常有幫助。

雖然使用 cubic-bezier ease 提供的兩個(gè)控制柄可以為簡單的動(dòng)畫獲得很好的效果,但是 JavaScript 允許多個(gè)控制柄,以此支持更多的變化。

以彈跳為例。在 CSS 中,我們必須聲明向上和向下的每個(gè)關(guān)鍵幀。在 JavaScript 中,我們可以通過在 greensock API(GSAP) 中聲明 bounce 來描述 ease 中所有這些移動(dòng) (其他 JS 庫有其他類型的 easing 默認(rèn)值)。

這里是 CSS 中用來實(shí)現(xiàn) bounce 的代碼 (來自 animate.css 的例子):

  1. @keyframes bounceInDown {
  2. from,
  3. 60%,
  4. 75%,
  5. 90%,
  6. to {
  7. animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
  8. }
  9. 0% {
  10. opacity: 0;
  11. transform: translate3d(0, -3000px, 0) scaleY(3);
  12. }
  13. 60% {
  14. opacity: 1;
  15. transform: translate3d(0, 25px, 0) scaleY(0.9);
  16. }
  17. 75% {
  18. transform: translate3d(0, -10px, 0) scaleY(0.95);
  19. }
  20. 90% {
  21. transform: translate3d(0, 5px, 0) scaleY(0.985);
  22. }
  23. to {
  24. transform: translate3d(0, 0, 0);
  25. }
  26. }
  27. .bounceInDown {
  28. animation-name: bounceInDown;
  29. }

下面是 JS 中使用 GreenSock 實(shí)現(xiàn)相同的 bounce:

  1. gsap.from(element, { duration: 1, ease: 'bounce.out', y: -500 })

我們將在之后章節(jié)的部分示例中使用 GreenSock。他們有一個(gè)很棒的 ease visualizer,幫助你建立精心制作的畫架。

#進(jìn)一步閱讀

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)