Vue 動畫:CSS 動畫原理 & animate.css 庫的使用 & 同時使用過渡和動畫 & Js 動畫與 Velocity.js 的結合 & 多個元素或組件的過渡 & 動畫封裝

Vue 中 CSS 動畫原理

<div id="app">
  <div v-if="show">hello world</div>
  <button @click="handleClick">切換</button>
</div>
<script>
  var vm = new Vue({
    el: '#app',
    data: {
      show: true
    },
    methods: {
      handleClick() {
        this.show = !this.show;
      }
    }
  })
</script>

現在希望 hello world 在隱藏和顯示的時候加上漸隱漸現的動畫效果。

在想要添加動畫的標籤外部添加 <transiton></transiton> 標籤,Vue 會自動幫助我們構建一個動畫的流程。

<transiton></transiton> 包裹的內容有一個過渡的動畫效果,可以通過 name 屬性給該標籤起一個名字。

  • 從隱藏狀態變成顯示狀態:
  • 從顯示狀態變成隱藏狀態:

fade-enter 中的前綴 fade 是 transition 中 name 定義的名字。如果 transition 沒有定義 name 屬性,前綴默認爲 v。即:v-enter,v-enter-active,……

<head>
  <style>
    .fade-enter, .fade-leave-to {
      opacity: 0;
    }
    .fade-enter-active, .fade-leave-active {
      transition: opacity 3s
    }
  </style>
</head>

<body>
  <div id="app">
    <transition name="fade">
      <div v-if="show">hello world</div>
    </transition>
    <button @click="handleClick">切換</button>
  </div>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        show: true
      },
      methods: {
        handleClick() {
          this.show = !this.show;
        }
      }
    })
  </script>
</body>

通過在某一時刻自動向 div 元素上增加一些 class 的底層原理,Vue 幫助我們實現了 CSS 過渡動畫效果。

在 Vue 中使用 animate.css 庫

使用 @keyframes 實現動畫效果

<head>
  <style>
    @keyframes bounce-in {
      0% {
        transform: scale(0)
      }
      50% {
        transform: scale(1.5)
      }
      100% {
        transform: scale(1)
      }
    }

    .fade-enter-active {
      transform-origin: left center;
      animation: bounce-in 1s;
    }
    .fade-leave-active {
      transform-origin: left center;
      animation: bounce-in 1s reverse;
    }
  </style>
</head>

<body>
  <div id="app">
    <transition name="fade">
      <div v-if="show">hello world</div>
    </transition>
    <button @click="handleClick">切換</button>
  </div>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        show: true
      },
      methods: {
        handleClick() {
          this.show = !this.show;
        }
      }
    })
  </script>
</body>

不使用 transition 標籤默認提供的類名

當使用 transition 標籤的時候,設置了 name=“fade”,它就會自動添加 fade-enter-active、fade-leave-active 這樣子的 class 的名字。

如果我想自定義 class,不用默認提供的命名規範可以嗎?

可以,只需要在 transition 外面自定義 class 名字:

<transition name="fade" enter-active-class="active" leave-active-class="leave">
  <div v-if="show">hello world</div>
</transition>
.active {
  transform-origin: left center;
  animation: bounce-in 1s;
}
.leave {
  transform-origin: left center;
  animation: bounce-in 1s reverse;
}

使用 animate.css 庫

<head>
  <!-- …… -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css">
</head>

<body>
  <div id="app">
    <transition name="fade" enter-active-class="animate__animated animate__swing"
      leave-active-class="animate__animated animate__shakeY">
      <div v-if="show">hello world</div>
    </transition>
    <button @click="handleClick">切換</button>
  </div>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        show: true
      },
      methods: {
        handleClick() {
          this.show = !this.show;
        }
      }
    })
  </script>
</body>
  • 引入 animate.css 動畫庫(教程:https://animate.style/#usage

    複雜的動畫不再需要自己去寫,直接用庫裏提供的動畫效果即可。

  • 必須使用自定義 class 名字的形式來使用 animate.css

  • class 類裏面必須包含 animate__animated 這樣一個具體的類,然後根據需求不同,把動畫效果的名字寫在第二個類名的位置。( enter-active-class="animate__animated animate__swing")

    動畫效果的名字可以在官網進行復制(點擊下圖中的複製符號即可)在這裏插入圖片描述

在 Vue 中同時使用過渡和動畫

如何在第一次加載顯示的時候也具備動畫的效果?

上面的例子中,只是在點擊按鈕的時候觸發動畫效果。如果想要在第一次加載顯示的時候也具備動畫的效果,該如何去做?

增加一個自定義的 class 名字 appear-active-class (也要同時增加 appear 屬性):

<transition 
	name="fade" 
	appear 
	enter-active-class="animate__animated animate__swing"
    leave-active-class="animate__animated animate__shakeY" 
    appear-active-class="animate__animated animate__swing"
>
  <div v-if="show">hello world</div>
</transition>

同時使用過渡和動畫

當 @keyframe 形式的動畫 (animate__swing) 執行的是 1s,transition 動畫執行的時間是 3s 時,整個動畫效果會按哪個時間顯示呢?

可以手動設置:(type="transition"

<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css">
  <style>
    .fade-enter,
    .fade-leave-to {
      opacity: 0;
    }
    .fade-enter-active,
    .fade-leave-active {
      transition: opacity 3s
    }
  </style>
</head>

<body>
  <div id="app">
    <transition type="transition" name="fade" appear
      enter-active-class="animate__animated animate__swing fade-enter-active"
      leave-active-class="animate__animated animate__shakeY fade-leave-active"
      appear-active-class="animate__animated animate__swing">
      <div v-if="show">hello world</div>
    </transition>
    <button @click="handleClick">切換</button>
  </div>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        show: true
      },
      methods: {
        handleClick() {
          this.show = !this.show;
        }
      }
    })
  </script>
</body>

上面是按照 transition 過渡動畫的時長作爲總時長,能否自定義動畫的時長呢?

自定義動畫的時長

<transition :duration="5000" name="fade" appear
  enter-active-class="animate__animated animate__swing fade-enter-active"
  leave-active-class="animate__animated animate__shakeY fade-leave-active"
  appear-active-class="animate__animated animate__swing">
  <div v-if="show">hello world</div>
</transition>

:duration="5000":5000 指的是毫秒。
點擊按鈕, 1s 動畫就執行完了,樣式依然存在,5s 後樣式纔會被清除。
:duration="{enter: 5000, leave: 10000}":出場動畫 10s 後被移除,入場動畫 5s 後 class 被清除。


Vue 中的 Js 動畫與 Velocity.js 的結合

上面的例子都是通過 CSS 實現的動畫效果,那有沒有辦法通過 JS 實現動畫效果呢?

有的,Vue 提供了一些 JS 動畫的鉤子。

JS 動畫

  • 入場動畫
    • @before-enter 當元素即將顯示的一瞬間,Vue 會自動觸發其綁定的事件。
    • @enter 當 @before-enter 被觸發結束之後,就要真正運行動畫。當真正開始運行動畫效果時,其所有的動畫會寫在 @enter 鉤子對應的回調函數裏面。
    • @after-enter 當 done 被調用後,Vue 會觸發 @after-enter 事件。
  • 出場動畫
    • @before-leave
    • @leave
    • @after-leave
<div id="app">
  <transition name="fade" @before-enter="handleBeforeEnter" @enter="handleEnter" @after-enter="handleAfterEnter">
    <div v-show="show">hello world</div>
  </transition>
  <button @click="handleClick">切換</button>
</div>
<script>
  var vm = new Vue({
    el: '#app',
    data: {
      show: true
    },
    methods: {
      handleClick() {
        this.show = !this.show;
      },
      handleBeforeEnter(el) { // el 指的是動畫包裹的div標籤  (當元素即將顯示的一瞬間,Vue會自動觸發handleBeforeEnter事件)
        el.style.color = "red";
      },
      handleEnter(el, done) {
        // 接收兩個參數:第一個參數 el,div的元素;第二個參數 done,回調函數  (當@before-enter被觸發結束之後,就要真正運行動畫,當真正開始運行動畫效果時,其所有的動畫會寫在@enter鉤子對應的回調函數handleEnter裏面)
        setTimeout(() => {
          el.style.color = "green";
          // done(); 爲了使效果明顯一點,寫在下面:4s時讓動畫結束
        }, 2000)
        setTimeout(() => {
          done(); // 當動畫結束時,要手動調用 done 這個回調函數,相當於告訴 Vue 動畫已經執行完了
        }, 4000)
      },
      handleAfterEnter(el) { //當 done 被調用後,Vue 會觸發 @after-enter 事件
        el.style.color = "black";
      }
    }
  })
</script>

JS 常用動畫庫:Velocity.js

下載 velocity.js 後用 <script></script> 標籤引入。

var vm = new Vue({
  el: '#app',
  data: {
    show: true
  },
  methods: {
    handleClick() {
      this.show = !this.show;
    },
    handleBeforeEnter(el) {
      el.style.opacity = 0;
    },
    handleEnter(el, done) {
      Velocity(el, {opacity: 1}, {duration: 1000, complete: done})
    },
    handleAfterEnter(el) {
      console.log("動畫結束")
    }
  }
})

在這裏插入圖片描述

Vue 中多個元素或組件的過渡動畫

多個元素的過渡動畫

.v-enter, .v-leave-to {
  opacity: 0;
}

.v-enter-active, .v-leave-active {
  transition: opacity 1s;
}
<div id="app">
 <transition>
    <div v-if="show" key="hello">hello world</div>
    <div v-else key="bye">bye world</div>
  </transition>
  <button @click="handleClick">切換</button>
</div>
<script>
  var vm = new Vue({
    el: '#app',
    data: {
      show: true
    },
    methods: {
      handleClick() {
        this.show = !this.show;
      }
    }
  })
</script>

transition 提供了 mode 屬性:

<transition mode="in-out">    // 先顯示再隱藏

多個組件的過渡動畫

<div id="app">
  <transition mode="in-out">
    <child v-if="show"></child>
    <child-one v-else></child-one>
  </transition>
  <button @click="handleClick">切換</button>
</div>
<script>
  Vue.component('child', {
    template: '<div>child</div>'
  })
  Vue.component('child-one', {
    template: '<div>child-one</div>'
  })
  var vm = new Vue({
    el: '#app',
    data: {
      show: true
    },
    methods: {
      handleClick() {
        this.show = !this.show;
      }
    }
  })
</script>
  • 也可以通過動態組件來實現:
<div id="app">
  <transition mode="in-out">
    <component :is="type"></component>
  </transition>
  <button @click="handleClick">切換</button>
</div>
<script>
  Vue.component('child', {
    template: '<div>child</div>'
  })
  Vue.component('child-one', {
    template: '<div>child-one</div>'
  })
  var vm = new Vue({
    el: '#app',
    data: {
      type: 'child'
    },
    methods: {
      handleClick() {
        this.type = this.type === 'child' ? 'child-one' : 'child';
      }
    }
  })
</script>

Vue 中的列表過渡

<div id="app">
  <div v-for="item of list" :key="item.id">
    {{item.title}}
  </div>
  <button @click="handleBtnClick">Add</button>
</div>
<script>
  var count = 0;
  var vm = new Vue({
    el: '#app',
    data: {
      list: []
    },
    methods: {
      handleBtnClick() {
        this.list.push({
          id: count++,
          title: 'hello world'
        })
      }
    }
  })
</script>

👆每點擊一個 Add 就會增加一條數據。
現在我們想往列表中增加內容時實現列表過渡的效果:

  • <transition-group></transition-group>:相當於在每一個 div 外層都加了一個 <transition></transition>
    <transition-group>
      <div v-for="item of list" :key="item.id">
        {{item.title}}
      </div>
    </transition-group>
    
  • .v-enter, .v-leave-to {
      opacity: 0;
    }
    
    .v-enter-active, .v-leave-active {
      transition: opacity 1s
    }
    

如果能不用 index 作爲 key 值,就不要用!!!


Vue 中的動畫封裝

如果我們覺得某一個動畫效果用的比較多,可以對這個動畫效果進行封裝。

.v-enter, .v-leave-to {
  opacity: 0;
}

.v-enter-active, .v-leave-active {
  transition: opacity 1s
}
<div id="app">
  <fade :show="show">
    <div>hello world</div>
  </fade>
  <button @click="handleBtnClick">切換</button>
</div>
<script>
  Vue.component('fade', {
    props: ['show'],
    template: `
      <transition>
        <slot v-if="show"></slot>
      </transition>
    `
  })
  var vm = new Vue({
    el: '#app',
    data: {
      show: false
    },
    methods: {
      handleBtnClick() {
        this.show = !this.show;
      }
    }
  })
</script>

👆 已經把動畫效果封裝到了 <fade></fade> 組件中,如果想再用這個動畫效果,可以直接複製 fade 組件的內容,傳不同的 dom 元素進去:

<fade :show="show">
  <h1>hello world</h1>
</fade>

樣式也可一起封裝到動畫組件中。
不用 css 動畫,轉而使用 js 動畫:

Vue.component('fade', {
  props: ['show'],
  template: `
    <transition @before-enter="handleBeforeEnter" @enter="handleEnter">
      <slot v-if="show"></slot>
    </transition>
  `,
  methods: {
    handleBeforeEnter(el) {
      el.style.color = "red";
    },
    handleEnter(el, done) {
      setTimeout(() => {
        el.style.color = "green";
        done();
      }, 2000)
    }
  }
})

可以完整的把所有的動畫的實現封裝在一個組件裏面。


更多 more:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章