Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.
In this article, we’ll look at how to add transitions when rendering lists.
List Transitions
If we want to apply transitions to render multiple items simultaneously with v-for
, we can use the transition-group
component.
Unlike transition
, it renders a span
by default. We can change the element that’s rendered with the tag
attribute.
Transition modes aren’t available because we aren’t alternating between mutually exclusive elements.
Elements inside are always required to have a unique key
attribute.
CSS transition classes will be applied to inner elements and not the group or container itself.
List Entering/Leaving Transitions
For example, we can make add a transition when adding or removing the item to a list as follows:
src/index.js
:
new Vue({
el: "#app",
data: {
items: [1, 2, 3],
nextNum: 4
},
methods: {
add() {
this.items.push(this.nextNum++);
},
remove() {
this.items.pop();
}
}
});
src/style.css
:
.list-enter-active,
.list-leave-active {
transition: all 1s;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(30px);
}
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link
rel="stylesheet"
type="text/css"
href="./src/styles.css"
media="screen"
/>
</head>
<body>
<div id="app">
<button @click="add">Add</button>
<button @click="remove">Remove</button>
<transition-group name="list" tag="p">
<span v-for="item in items" :key="item">
{{ item }}
</span>
</transition-group>
</div>
<script src="src/index.js"></script>
</body>
</html>
Then when we click the Add button, we see a number added to the end of the list. When we click Remove, the rightmost number is removed.
Like transition
, we defined the classes prefixed with the name
we specified.
Also, we specified the tag
name so that we have a span
element rendered for each item within the p
element.
List Move Transitions
transition-group
can animate the change in position, in addition, to enter and leave. We can do this with the addition of the v-move
class.
Like other classes, we prefix it with the name
attribute and we can also manually specify a class with the move-class
attribute.
For example, we can add an effect when we shuffle the position of numbers as follows:
src/index.js
:
new Vue({
el: "#app",
data: {
items: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
},
methods: {
shuffle() {
this.items = _.shuffle(this.items);
}
}
});
src/styles.css
:
.flip-list-move {
transition: transform 1s;
}
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
<link rel="stylesheet" type="text/css" href="./src/styles.css" />
</head>
<body>
<div id="app">
<button @click="shuffle">Shuffle</button>
<transition-group name="flip-list" tag="div">
<div v-for="item in items" :key="item">
{{ item }}
</div>
</transition-group>
</div>
<script src="src/index.js"></script>
</body>
</html>
When we click Shuffle, we see the shuffling is stretched slightly in time.
Vue uses FLIP to smoothly transition between elements from the old position to their new position.
They don’t work with elements set to display: inline
, we have to use display: inline-block
or place elements in a flexbox container.
Staggering List Transitions
We can stagger list transitions as follows:
src/index.js
:
new Vue({
el: "#app",
data: {
items: ["foo", "bar", "baz"],
query: ""
},
computed: {
filteredItems() {
if (!this.query) {
return this.items;
}
return this.items.filter(i => i === this.query);
}
},
methods: {
beforeEnter(el) {
el.style.opacity = 0;
el.style.height = 0;
},
enter(el, done) {
var delay = el.dataset.index * 150;
setTimeout(() => {
Velocity(el, { opacity: 1, height: "1.6em" }, { complete: done });
}, delay);
},
leave(el, done) {
var delay = el.dataset.index * 150;
setTimeout(() => {
Velocity(el, { opacity: 0, height: 0 }, { complete: done });
}, delay);
}
}
});
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>App</title>
<meta charset="UTF-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
</head>
<body>
<div id="app">
<input v-model="query" />
<transition-group
name="flip-list"
tag="div"
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
>
<div v-for="item in filteredItems" :key="item">
{{ item }}
</div>
</transition-group>
</div>
<script src="src/index.js"></script>
</body>
</html>
We can see that we now have transitions when the list is being filtered.
Conclusion
We can create transitions when rendering a list with v-for
like we do with v-if
.
The difference is that we have to specify the tag name of the container if we don’t want to render a span.
Also, we always have to add the key
attribute to each element inside.
We can have transitions when changing element position by specifying the CSS style for the v-move
class, which can be renamed if we specify the class prefix or name.
Specifying enter and leave transitions or v-for
is the same as specifying enter and leave transitions for v-if
.
Finally, we can create transitions with JavaScript with Velocity.js just like v-if
animations.