Categories
Vue 3

Vue 3 — List Transitions

Spread the love

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at creating list transitions.

List Move Transitions

We can add list move transitions.

For instance, we can use the transition-group component to display some effect when we the items change position:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
    <style>
      .list-move {
        transition: transform 0.8s ease;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <button @click="shuffle">shuffle</button>
      <transition-group name="list" tag="div">
        <p v-for="item in items" :key="item">
          {{ item }}
        </p>
      </transition-group>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            items: Array(10)
              .fill()
              .map(() => Math.random()),
          };
        },
        methods: {
          shuffle() {
            this.items = _.shuffle(this.items);
          }
        }
      });
      app.mount("#app");
    </script>
  </body>
</html>

We added the list-move class with our transition effect to display it when the list is shuffled.

The list is shuffled with the Lodash shuffle method.

Staggering List Transitions

We can stagger transitions in a list.

To do that, we use the Greensock library to help us.

We can write;

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.4/gsap.min.js"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="query" />
      <transition-group
        name="fade"
        tag="div"
        :css="false"
        @before-enter="beforeEnter"
        @enter="enter"
        @leave="leave"
      >
        <p
          v-for="(item, index) in computedList"
          :key="item.name"
          :data-index="index"
        >
          {{ item.name }}
        </p>
      </transition-group>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            query: "",
            list: [
              { name: "james" },
              { name: "mary" },
              { name: "alex" },
              { name: "bob" },
              { name: "jane" }
            ]
          };
        },
        computed: {
          computedList() {
            return this.list.filter(item => {
              return item.name.toLowerCase().includes(this.query.toLowerCase());
            });
          }
        },
        methods: {
          beforeEnter(el) {
            el.style.opacity = 0;
            el.style.height = 0;
          },
          enter(el, done) {
            gsap.to(el, {
              opacity: 1,
              height: "1.3em",
              delay: el.dataset.index * 0.55,
              onComplete: done
            });
          },
          leave(el, done) {
            gsap.to(el, {
              opacity: 0,
              height: 0,
              delay: el.dataset.index * 0.45,
              onComplete: done
            });
          }
        }
      });
      app.mount("#app");
    </script>
  </body>
</html>

We included the Greensock library with our app.

In the methods property, we have a few methods.

The beforeEnter method sets the container’s opacity and height to 0.

The enter method has our enter animation effect.

We change the opacity to 1 to make opaque.

height is th height of the container.

delay is the delay of the animation.

onComplete is a function we call to notify Vue that the animation is done.

We do the same thing with the leave transition.

When computedList returns a new value, the animation effects will be applied.

Therefore, when we type in something into the input box, we’ll see the effects applied.

Reusable Transitions

We can make our transitions reusable by moving it into our own component.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.3.4/gsap.min.js"></script>
  </head>
  <body>
    <div id="app">
      <input v-model="query" />
      <list-transition>
        <p
          v-for="(item, index) in computedList"
          :key="item.name"
          :data-index="index"
        >
          {{ item.name }}
        </p>
      </list-transition>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            query: "",
            list: [
              { name: "james" },
              { name: "mary" },
              { name: "alex" },
              { name: "bob" },
              { name: "jane" }
            ]
          };
        },
        computed: {
          computedList() {
            return this.list.filter(item => {
              return item.name.toLowerCase().includes(this.query.toLowerCase());
            });
          }
        }
      }); 

      app.component("list-transition", {
        template: `
        <transition-group
          name="fade"
          tag="div"
          :css="false"
          @before-enter="beforeEnter"
          @enter="enter"
          @leave="leave"
        >
         <slot></slot>
        </transition-group>
        `,
        methods: {
          beforeEnter(el) {
            el.style.opacity = 0;
            el.style.height = 0;
          },
          enter(el, done) {
            gsap.to(el, {
              opacity: 1,
              height: "1.3em",
              delay: el.dataset.index * 0.55,
              onComplete: done
            });
          },
          leave(el, done) {
            gsap.to(el, {
              opacity: 0,
              height: 0,
              delay: el.dataset.index * 0.45,
              onComplete: done
            });
          }
        }
      }); 

      app.mount("#app");
    </script>
  </body>
</html>

to move our transition component and hooks to its own component.

We just create a component and add a slot in between the transition-group tags to add the slot for our content.

Now we can use the list-transition component everywhere.

Conclusion

We can add our list transitions effects with the transition-group component.

It takes various directives to let us add hooks to create JavaScript animations.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *