This is the 16th day of my participation in the August Text Challenge.More challenges in August

During development, we wanted to add some kind of transition animation to the display and disappearance of a component, which would add to the user experience

  • The React framework does not provide any animation apis, so we need to use a third-party library called React-transition-group to animate React
  • Vue provides us with some built-in components and corresponding apis to complete animation, using which we can easily achieve transition animation effects

Transition animations

Vue provides a wrapper component for Transition, and you can add an entry/exit transition to any element or component in the following cases

<template>
  <div>
    <button @click="isShow = ! isShow">show/hidden</button>

    <! -- During the animation execution stage, only the start state (start frame) and end state (end frame) are defined, and then the transition effect between the start frame and end frame is set, so the whole animation can be considered as a transition animation.
    <transition name="fade">
      <h2 v-if="isShow">message</h2>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'App'.data() {
    return {
      isShow: true}}}</script>

<style scoped>
/* When the animation is actually executed, vue will automatically add the corresponding animation effect.[Transtiton component set name value]-[style suffix] */
.fade-enter-from..fade-leave-to {
  opacity: 0;
}

/* By default, this part of the style is the browser's default Settings, so this part of the style can be omitted without any writing */
/* .fade-leave-from, .fade-enter-to { opacity: 1; } * /
  
.fade-enter-active..fade-leave-active {
  transition: opacity 2s ease;
}
</style>
Copy the code

The class name is named as follows:

  • If we use a transition without a name, then all classes are prefixed with v- by default
  • If we add a name attribute, for example<transtion name="foo">, then all classes will start with foo-At the beginning

Transition animation class

When inserting or deleting elements contained in the Transition component, Vue does the following

  • Automatically sniff out whether the target element has CSS transitions or animations applied, and if so, add/remove CSS class names when appropriate
  • If the Transition component provides JavaScript hook functions, these hook functions will be called at the appropriate time
  • If the JavaScript hook is not found and CSS transitions/animations are not detected, DOM insertion and deletion will be performed immediately
Style name Effective time The failure time instructions
v-enter-from Takes effect before the element is inserted The element is removed the next frame after it is inserted Define the beginning state of the transition
v-enter-to The next frame takes effect after the element is inserted

(At the same time the v-enter-from was removed)
Remove after the transition/animation is complete Define the end state of the transition
v-enter-active Applied throughout the transition phase,

Takes effect before the element is inserted
Remove when transition/animation is complete Defines the state in which the transition takes effect

This class can be used to define the process time, delay, and curve functions that enter the transition
v-leave-from Takes effect immediately when exit transition is triggered The next frame is removed Define the beginning of the exit transition
v-leave-to Applied throughout the transition phase of departure,

Takes effect immediately when exit transition is triggered
Remove after the transition/animation is complete Leaving the end state of transition

This class can be used to define exit transition process time, delay and curve functions
v-leave-active Removal after transition/animation is complete takes effect on the next frame after departure transition is triggered

(At the same time the V-leave-from was deleted)
Remove after the transition/animation is complete Defines the state when the exit transition takes effect

The animate animated

<template>
  <div>
    <! Div is wrapped to wrap with h2 below -->
    <div>
      <button @click="isShow = ! isShow">show/hidden</button>
    </div>

    <transition name="fade">
      <! H2 must be set to an inline element or a block element. The default is a block element, so the style is applied to the entire line of h2 and the content is not displayed in the entire line, so the animation effect will be different.
      <h2 v-if="isShow">message</h2>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'App'.data() {
    return {
      isShow: true}}}</script>

<style scoped>
h2 {
  display: inline-block;
}

.fade-enter-active {
  animation: bounce 1s ease;
}

.fade-leave-active {
  animation: bounce 1s ease reverse;
}

/* Define frame animation */
@keyframes bounce {
  0% {
    transform: scale(0);
  }

  50% {
    transform: scale(1.2);
  }

  100% {
    transform: scale(1); }}</style>
Copy the code

The animation properties

type

Vue internally listens for transitionEnd or AnimationEnd to know that the transition is complete, depending on the CSS rules applied to the element

If we use only one of them, Vue automatically identifies the type and sets up a listener

But if we use both transitions and animations, in this case one animation may end before the other animation ends

In this case, we can explicitly tell the Vue what type to listen to by setting the type property to animation or Transition

<transition name="fade" type="animation">
  <h2 v-if="isShow">message</h2>
</transition>
Copy the code
duration

We can also specify the duration of the transition explicitly, via the Duration property.

Duration can be set to two types of values

  • Number type: Sets the transition time for both entry and exit
<transition name="fade" :duration="3000">
  <h2 v-if="isShow">message</h2>
</transition>
Copy the code
  • Object: Sets the transition time for entering and leaving respectively
<transition name="fade" :duration="{enter: 1000, leave: 2000}">
  <h2 v-if="isShow">message</h2>
</transition>
Copy the code
mode

By default, the entry and exit animations occur simultaneously

Problems with switching between two elements

We don’t want to animate both entry and exit at the same time, so we need to set the transition mode:

  • In-out: The new element transitions first, and then the current element transitions away
  • Out-in: The current element transitions first, and then the new element transitions in
<transition name="fade" mode="out-in">
  <h2 v-if="isShow">message</h2>
  <h2 v-else>msg</h2>
</transition>
Copy the code
appear

By default, the first rendering is rendered without animation

If we want to animate it, we can add another attribute, “Appear.

<! -- Appear is a Boolean value. The default is false -->
<! So: Appear ="true" -->
<transition name="fade" mode="out-in" appear>
  <Home v-if="isShow" />
  <About v-else />
</transition>
Copy the code

animate.css

It would be inefficient to write these animations one by one, so in development we might refer to some third-party library such as animation.css

Animate. CSS is a ready-made, cross-platform animation library for our Web projects, useful for emphasis, homepages, swipes, and attention guides

How do I use the Animate library?

  • Step 1: You need to install the animate. CSS library
  • Step 2: Import styles from the animate. CSS library
  • Step 3: Use an Animation or animate class

main.js

import { createApp } from 'vue'
import App from './App.vue'

// Globally introduce animation-related styles
import 'animate.css'

createApp(App).mount('#app')
Copy the code

App.vue

<template>
  <div>
    <div>
      <button @click="isShow = ! isShow">show/hidden</button>
    </div>

    <transition name="fade" mode="out-in">
      <Home v-if="isShow" />
      <About v-else />
    </transition>
  </div>
</template>

<script>
import About from './components/About.vue'
import Home from './components/Home.vue'

export default {
  name: 'App'.components: {
    Home,
    About
  },

  data() {
    return {
      isShow: true}}}</script>

<style scoped>
h2 {
  display: inline-block;
}

.fade-enter-active {
  /* The style name can be retrieved from the animate. CSS website */
  animation: bounceInDown 1s ease;
}

.fade-leave-active {
  animation: zoomOut 1s ease;
}
</style>
Copy the code

We can also customize the transition class name using the following attributes

  • enter-from-class
  • enter-active-class
  • enter-to-class
  • leave-from-class
  • leave-active-class
  • leave-to-class

They take precedence over ordinary class names, which is useful for Vue’s transition system and other third-party CSS animation libraries such as animation.css. Used in combination, ten points are useful.

<template>
  <div>
    <div>
      <button @click="isShow = ! isShow">show/hidden</button>
    </div>

    <! Animate__animated is the public style set by animate. CSS -->
    <transition
      mode="out-in"
      enter-active-class="animate__animated animate__fadeIn"
      leave-active-class="animate__animated animate__fadeOut"
    >
      <Home v-if="isShow" />
      <About v-else />
    </transition>
  </div>
</template>

<script>
import About from './components/About.vue'
import Home from './components/Home.vue'

export default {
  name: 'App'.components: {
    Home,
    About
  },

  data() {
    return {
      isShow: true}}}</script>

<style scoped>
h2 {
  display: inline-block;
}

.fade-enter-active {
  animation: bounceInDown 1s ease;
}

.fade-leave-active {
  animation: zoomOut 1s ease;
}
</style>
Copy the code

gsap

Before using the animation, let’s take a look at the JavaScript hooks provided by the Transition component. These hooks help us listen to what stage the animation is at

Note:

  1. When we use JavaScript to perform transition animations, we need to do the done callback

  2. Adding: CSS =”false” will also cause Vue to skip CSS detection,

    Vue will no longer set and check CSS styles for animations

    In addition to slightly better performance, this avoids the impact of CSS rules during the transition

  3. Each hook function takes an argument, EL, that represents the element currently performing the animation

  4. For the Enter and leave constructors, there are two arguments:

    • Parameter 1 –> EL is the element that performs the animation

    • Argument 2 –> done is a function that needs to be called to show vue that the corresponding animation life cycle function has finished executing

In some cases we want to use JavaScript to achieve some animation effects, in which case we can use the GSAP library.

What is GSAP

  • GSAP stands for The GreenSock Animation Platform
  • It animates CSS properties, SVG, Canvas, etc., via JavaScript, and is browser-compatible

How should this library be used

  • Step 1: You need to install the GSAP library
  • Step 2: Import the GSAP library
  • Step 3: Use the corresponding API
<template>
  <div>
    <div>
      <button @click="isShow = ! isShow">show/hidden</button>
    </div>

    <transition
      mode="out-in"
      @enter="handleEnter"
      @leave="handleLeave"
      :css="false"
    >
      <Home v-if="isShow" />
      <About v-else />
    </transition>
  </div>
</template>

<script>
import About from './components/About.vue'
import Home from './components/Home.vue'
import gsap from 'gsap'

export default {
  name: 'App'.components: {
    Home,
    About
  },

  data() {
    return {
      isShow: true}},methods: {
    // Both enter and leave callbacks take two arguments
    // Parameter 1: the element to perform the callback
    // Parameter 2: Manually tell vue that the animation is finished, otherwise the corresponding animation will continue to be executed, affecting subsequent animation execution
    handleEnter(el, done) {
      // What state does the from function represent to restore to the original state
      gsap.from(el, {
        scale: 1.2.opacity: 0.onComplete: done
      })
    },

    handleLeave(el, done) {
      // What state does the initial state need to change to
      gsap.to(el, {
        scale: 1.2.opacity: 0.onComplete: done
      })
    }
  }
}
</script>

<style scoped>
h2 {
  display: inline-block;
}

.fade-enter-active {
  animation: bounceInDown 1s ease;
}

.fade-leave-active {
  animation: zoomOut 1s ease;
}
</style>
Copy the code

Gsap implements numerical variation

In some projects, we will see animations of rapidly changing numbers that can be easily implemented via GSAP

<template>
  <div style="display: inline-block">
    <! ToFixed removes the decimal point every time it changes by default, so use toFixed to remove the decimal point and perform the round operation -->
    <div>{{ counter.toFixed(0) }}</div>
    <button @click="increment">+ 100</button>
  </div>
</template>

<script>
import gsap from 'gsap'

export default {
  name: 'Home'.data() {
    return {
      counter: 0}},methods: {
    increment() {
      // The first argument to the to method can be an object
      // It takes 2s to grow the value of 100
      // The change is couter + 100
      gsap.to(this, { duration: 2.counter: this.counter + 100})}}}</script>
Copy the code

The list of operations

All of the previous transitions were for a single element or component

  • Or a single node
  • Or one of several nodes is rendered at the same time

What if you want to render a list, and you want to animate adding and deleting data to that list?

We use the
component to do this;

Using
has the following characteristics:

  • By default, it does not render an element wrapper, but you can specify an element and render it with a tag attribute

  • Transition modes (in-out and out-in) are not available because we no longer switch unique elements between each other

  • Internal elements always need to provide a unique key attribute value that identifies which element the animation needs to be added to

  • CSS transitioning classes will be applied to internal elements, not the group/container itself

The basic use

Case study:

  1. A list of numbers that can be added or removed
  2. Animate the added and removed numbers as they are added and removed

<template>
<div>
  <button @click="add">add</button>
  <button @click="remove">remove</button>
  <button @click="shuffle">shuffle</button>

  <transition-group tag="ul" name="foo">
    <li v-for="item in list" :key="item">
      {{ item }}
    </li>
  </transition-group>
</div>
</template>

<script>
import _ from 'lodash'

export default {
name: 'App'.data() {
  return {
    list: [0.1.2.3.4.5.6.7.8.9].length: 10}},methods: {
  add() {
    this.list.splice(this.getRandomIndex(), 0.this.length++)
  },

  remove() {
    this.list.splice(this.getRandomIndex(), 1)},shuffle() {
    / / shuffle
    this.list = _.shuffle(this.list)
  },

  getRandomIndex() {
    return Math.floor(Math.random() * this.list.length) + 1}}}</script>

<style scoped>
ul.li {
  list-style: none;
  margin: 0;
  padding: 0;
}

ul {
  /* ul cannot be set to flex layout because subsequent li elements may be set to relative position when moving. In flex layout, the following elements are automatically filled in and absolute elements are automatically moved to the top of the list (relative to left: 0) this will cause corresponding interference to animation execution */
  /* display: flex; * /
  margin-top: 10px;
}

li {
  margin-right: 10px;
  display: inline-block;
}

.foo-enter-from..foo-leave-to {
  opacity: 0;
  transform: translateY(30px);
}

.foo-enter-active..foo-leave-active {
  transition: all 1s ease;
}

.foo-leave-active {
  / * by default, at the time of removing elements, elements can't be left behind moving picture Because is has not been timely remove elements that need to wait for element removed in displacement This animation is pointing in the direction of time, so there will be a flash effect So this time can be set to leave element positioning, let them out of the standard flow, There is no way to block subsequent elements from moving to the left, making way for the */ to move the drawing and remove the animation at the same time
  
  position: absolute;
}


/* By default, new and removed nodes are animated, but other nodes that need to be moved are not animated, so we need to add this style class, which is used to animate before and after inserting and removing nodes. It will apply when the element changes position and just like the name before, we can customize the prefix */ by name
.foo-move {
  /* Vue automatically calculates the rest of the attributes */
  transition: transform 1s ease;
}
</style>
Copy the code

Staggered transition case

<template>
  <div>
    <input type="text" v-model="search">
    <transition-group
      tag="ul"
      name="list"
      @before-enter="beforeEnter"
      @enter="handleEnter"
      @leave="handleLeave"
      :css="false"
    >
      <! Set a custom property so that the index value of li can be obtained in js code -->
      <li v-for="(user, index) in showUsers" :key="user" :data-index="index">{{ user }}</li>
    </transition-group>
  </div>
</template>

<script>
import gsap from 'gsap'

export default {
  name: 'App'.data() {
    return {
      search: ' '.users: ['Bruce Lee'.'Jackie Chan'.'Chuck Norris'.'Jet Li'.'Kung Fury']}},computed: {
    showUsers() {
      return this.users.filter(user= > user.includes(this.search))
    }
  },

  methods: {
    beforeEnter(el) {
      el.style.height = '0px'
      el.style.opacity = '0'
    },

    handleEnter(el, done) {
      // Let's use the gSAP delay property to implement an alternate disappearing animation
      gsap.to(el, {
        height: '1.5 em'.opacity: 1.delay: el.dataset.index * 0.1.// Get the index, so that the delay value is incremented successively
        onComplete: done
      })
    },

    handleLeave(el, done) {
      gsap.to(el, {
        height: 0.opacity: 0.delay: el.dataset.index * 0.1.onComplete: done
      })
    }
  }
}
</script>
Copy the code