VueJS – Transition và Animation

VueJS cung cấp nhiều cách khác nhau để thêm các hiệu ứng transition khi các phần tử được thêm,update hay gỡ bỏ khỏi DOM.

Transition

VueJS cũng cung cấp sẵn transition component. Chỉ cần bao quanh các phần tử cần tạo hiệu ứng.

Cấu trúc

<transition name = "nameoftransition">
   <div></div>
</transition>

Ví dụ

<html>
   <head>
      <title>VueJs Instance</title>
      <script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
   </head>
   <body>
      <style>
         .fade-enter-active, .fade-leave-active {
            transition: opacity 2s
         }
         .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
            opacity: 0
         }
      </style>
      <div id = "databinding">
         <button v-on:click = "show = !show">Click Me</button>
         <transition name = "fade">
            <p v-show = "show" v-bind:style = "styleobj">Animation Example</p>
         </transition>
      </div>
      <script type = "text/javascript">
         var vm = new Vue({
            el: '#databinding',
            data: {
               show:true,
               styleobj :{
                  fontSize:'30px',
                  color:'red'
               }
            },
            methods : {
            }
         });
      </script>
   </body>
</html>

Trong code trên, chung ta có 1 button, khi click vào nó sẽ thay đổi biến show từ true sang false hay ngược lại. Biến show này mặc định có giá trị true trong data. Một tag <p> sẽ hiển thị khi biến show có giá trị true. Và nó được bao trong transition element.

<transition name = "fade">
	<p v-show = "show" v-bind:style = "styleobj">Animation Example</p>
</transition>

Tên của transitionfade. VueJS cung cấp các class thực hiện hiệu ứng chuyển đổi. Các class này có có tiền tố là tên của transition (Ở đây sẽ là fade, tên transition chúng ta đã đặt).

Các class này bao gồm:

  • v-enter : Trạng thái bắt đầu của enter.
  • v-enter-active : Trạng thái active của enter, Dùng định nghĩa delay, duration, và easing.
  • v-enter-to (2.1.8+) : Trạng thái kết thúc của enter.
  • v-leave : Trạng thái bắt đầu của leave.
  • v-leave-active : Trạng thái active của leave, Dùng định nghĩa delay, duration, và easing.
  • v-leave-to (2.1.8+) : Trạng thái kết thúc của leave.

Ở đây prefix v- là mặc định khi bạn dùng một thẻ <transition> không có tên. Còn khi đặt tên cho transition thì thay v bằng tên của transition.

Chúng ta có định nghĩa styte của quá trình transition.

<style>
   .fade-enter-active, .fade-leave-active {
      transition: opacity 2s
   }
   .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
      opacity: 0
   }
</style>

.fade_enter_active.fade_leave_active sẽ thay đổi opacity trong 2 giây khi element thêm vào hay xóa đi. Bắt đầu hay kết thúc quá trình .fade-enter, .fade-leave-to có opacity là 0.

Khi click vào button

Sau 2 giây, quá trình chuyển đổi kết thúc.

Ví dụ 2

Ví dụ này sẽ tạo hiệu ứng image di chuyển trên trục x khi click button.

<html>
   <head>
      <title>VueJs Instance</title>
      <script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
   </head>
   <body>
      <style>
         .shiftx-enter-active, .shiftx-leave-active {
            transition: all 2s ease-in-out;
         }
         .shiftx-enter, .shiftx-leave-to /* .fade-leave-active below version 2.1.8 */ {
            transform :  translateX(100px);
         }
      </style>
      <div id = "databinding">
         <button v-on:click = "show = !show">Click Me</button>
         <transition name = "shiftx">
            <p v-show = "show">
               <img src = "images/img.jpg" style = "width:100px;height:100px;" />
            </p>
         </transition>
      </div>
      <script type = "text/javascript">
         var vm = new Vue({
            el: '#databinding',
            data: {
               show:true
            },
            methods : {
            }
         });
      </script>
   </body>
</html>

Tên transition này là shiftx. Transform sẽ di chuyển image theo trục x 100px.

<style>
   .shiftx-enter-active, .shiftx-leave-active {
      transition: all 2s ease-in-out;
   }
   .shiftx-enter, .shiftx-leave-to /* .fade-leave-active below version 2.1.8 */ {
      transform :  translateX(100px);
   }
</style>

Kết quả.

Khi click button, image sẽ di chuyển sang phải 100px.

Animation

Animation cũng tương tự transition. Xem ví dụ sau:

<html>
   <head>
      <title>VueJs Instance</title>
      <script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
   </head>
   <body>
      <style>
         .shiftx-enter-active {
            animation: shift-in 2s;
         }
         .shiftx-leave-active {
            animation: shift-in 2s reverse;
         }
         @keyframes shift-in {
            0%   {transform:rotateX(0deg);}
            25%  {transform:rotateX(90deg);}
            50%  {transform:rotateX(120deg);}
            75%  {transform:rotateX(180deg);}
            100% {transform:rotateX(360deg);}
         }
      </style>
      <div id = "databinding">
         <button v-on:click = "show = !show">Click Me</button>
         <transition name = "shiftx">
            <p v-show = "show">
               <img src = "images/img.jpg" style = "width:100px;height:100px;" />
            </p>
         </transition>
      </div>
      <script type = "text/javascript">
         var vm = new Vue({
            el: '#databinding',
            data: {
               show:true
            },
            methods : {
            }
         });
      </script>
   </body>
</html>

Trong ví dụ trên, ta có 1 image trong thẻ p với tên transitionshiftx. Các class cũng tương tự như transition.

<style>
   .shiftx-enter-active {
      animation: shift-in 2s;
   }
   .shiftx-leave-active {
      animation: shift-in 2s reverse;
   }
   @keyframes shift-in {
      0%   {transform:rotateX(0deg);}
      25%  {transform:rotateX(90deg);}
      50%  {transform:rotateX(120deg);}
      75%  {transform:rotateX(180deg);}
      100% {transform:rotateX(360deg);}
   }
</style>

Các class cũng có tiếp đầu ngữ là tên của <transition>

Kết quả

Khi click nó sẽ xoay 0 đến 360° trước khi biến mất.

Custom Class trong Transition

VueJS cung cấp các thuộc tính để chỉ định các class cho transition:

  • enter-class
  • enter-active-class
  • enter-to-class (2.1.8+)
  • leave-class
  • leave-active-class
  • leave-to-class (2.1.8+)

Nó giúp bạn kết hợp transition của Vue với các thư viện CSS animation như Animate.css.

Ví dụ

<html>
   <head>
      <link href = "https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel = "stylesheet" type = "text/css">
      <script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
   </head>
   <body>
      <div id = "animate" style = "text-align:center">
         <button @click = "show = !show"><span style = "font-size:25px;">Animate</span></button>
         <transition
            name = "custom-classes-transition"
            enter-active-class = "animated swing"
            leave-active-class = "animated bounceIn">
            <p v-if = "show"><span style = "font-size:25px;">Example</span></p>
         </transition>
      </div>
      <script type = "text/javascript">
         var vm =  new Vue({
            el: '#animate',
            data: {
               show: true
            }
         });
      </script>
   </body>
</html>

Ở trên, chúng ta dùng 2 animations của thư viện bên ngoài lại enter-active-class = “animated swing”leave-active-class = “animated bounceIn”.

Chỉ định thời gian cho Transition.

Khi chúng ta sử dụng transition hay animation trong VueJS. Vue sẽ đợi sự kiện transionend hay animationend khi animation, transition kết thúc. Tuy nhiên trong vài trường hợp nó có thể bị delay. Chúng ta thêm duration, hay chỉ định thời gian cho quá trình enterleave như code bên dưới.

<transition :duration = "1000"></transition>
<transition :duration = "{ enter: 500, leave: 800 }">...</transition>

JavaScript Hooks

Trong component transition bạn cũng có thể dùng các function JavaScript để tạo animation bằng JavaScript.

<html>
   <head>
      <title>VueJs Instance</title>
      <script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
   </head>
   <body>
      <script src = "https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
      <div id = "example-4">
         <button @click = "show = !show">
            <span style = "font-size:25px;">Toggle</span>
         </button>
         <transition  v-on:before-enter = "beforeEnter"
            v-on:enter = "enter"
            v-on:leave = "leave"
            v-bind:css = "false">
            <p v-if = "show" style = "font-size:25px;">Animation Example with velocity</p>
         </transition>
      </div>
      <script type = "text/javascript">
         var vm = new Vue({
            el: '#example-4',
            data: {
               show: false
            },
            methods: {
               beforeEnter: function (el) {
                  el.style.opacity = 0
               },
               enter: function (el, done) {
                  Velocity(el, { opacity: 1, fontSize: '25px' }, { duration: 1000 })
                  Velocity(el, { fontSize: '10px' }, { complete: done })
               },
               leave: function (el, done) {
                  Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 1500 })
                  Velocity(el, { rotateZ: '100deg' }, { loop: 2 })
                  Velocity(el, {
                     rotateZ: '45deg',
                     translateY: '30px',
                     translateX: '30px',
                     opacity: 0
                  }, { complete: done })
               }
            }
         });
      </script>
   </body>
</html>

Trong ví dụ này, mình dùng Velocity.js, cũng tương tự như jQuery.animate, Velocity tạo animation cùng các function js.

<transition  
   v-on:before-enter = "beforeEnter"
   v-on:enter = "enter"
   v-on:leave = "leave"
   v-bind:css = "false">
   <p v-if = "show" style = "font-size:25px;">Animation Example with velocity</p>
</transition>

Kết quả:

Thuộc tính v-bind:css = “false” giúp VueJS hiểu đây là quá trình sử dụng JSVueJS có thể bỏ qua phần dò tìm CSS. Việc này cũng giúp các CSS không can thiệp vào quá trình transition,

Tiếp đầu ngữ v-on cũng được thêm vào tên của các sự kiện như before-enter, enter, leave

Transition khi render lần đầu tiên

Để tạo animation ngay lúc render, bạn có thể sử dụng thuộc tính appear trong transition.

<html>
   <head>
      <link href = "https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel = "stylesheet" type = "text/css">
      <script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
   </head>
   <body>
      <div id = "animate" style = "text-align:center">
         <transition
            appear
            appear-class = "custom-appear-class"
            appear-active-class = "animated bounceIn">
            <h1>BounceIn - Animation Example</h1>
         </transition>
         <transition
            appear
            appear-class = "custom-appear-class"
            appear-active-class = "animated swing">
            <h1>Swing - Animation Example</h1>
         </transition>
         <transition
            appear
            appear-class = "custom-appear-class"
            appear-active-class = "animated rubberBand">
            <h1>RubberBand - Animation Example</h1>
         </transition>
      </div>
      <script type = "text/javascript">
         var vm =  new Vue({
            el: '#animate',
            data: {
               show: true
            }
         });
      </script>
   </body>
</html>

Trong ví dụ trên, mình sử dụng 3 animation khác nhau từ thư viện animate.css với thuộc tính appear trong <transition> kết quả animation sẽ chạy ngay khi render.

Animation Components

Chúng ta có thể sử dụng components trong transition bằng code sau. Chúng ta sẽ sử dụng dynamic component.

<html>
   <head>
      <title>VueJs Instance</title>
      <script type = "text/javascript" src = "https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
      <link href = "https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel = "stylesheet" type = "text/css">
   </head>
   <body>
      <div id = "databinding" style = "text-align:center;">
         <transition  appear
            appear-class = "custom-appear-class"
            appear-active-class = "animated wobble">
            <component v-bind:is = "view"></component>
         </transition>
      </div>
      <script type = "text/javascript">
         var vm = new Vue({
            el: '#databinding',
            data: {
               view: 'component1'
            },
            components: {
               'component1': {
                  template: '<div><span style = "font-size:25;color:red;">Animation on Components</span></div>'
               }
            }
         });
      </script>
   </body>
</html>

Kết quả