'Group transition with dynamic list as a whole
I have a data_sets. I need to take out a certain dataset (data_source in the snipped), filter it (itemList in the snippet) and display it, with any simple group transition, preferably list transition in Vue's official guide
This is a snippet that I created on https://sfc.vuejs.org/ to play around.
<template>
<div>
<ul>
<transition-group name="list" mode="out-in">
<li v-for="item in itemList" :key="item.id">
{{item.content}}
</li>
</transition-group>
</ul>
</div>
<button @click="changeDatasource(0)">
Dataset 1
</button>
<button @click="changeDatasource(1)">
Dataset 2
</button>
<button @click="changeDatasource(2)">
Dataset 3
</button>
</template>
<script>
export default {
data() {
return {
data_sets: [
[{
id: 1,
content: "Frog",
active: 1,
},
{
id: 2,
content: "Elephant",
active: 0,
},
{
id: 3,
content: "Racoon",
active: 1,
},
{
id: 8,
content: "Cheetah",
active: 1,
},
],
[{
id: 4,
content: "Rooster",
active: 1,
},
{
id: 5,
content: "Cow",
active: 1,
},
{
id: 6,
content: "Cat",
active: 1,
},
{
id: 7,
content: "Dog",
active: 0,
},
],
[{
id: 10,
content: "Lion",
active: 1,
},
{
id: 11,
content: "Shark",
active: 1,
},
{
id: 12,
content: "Bee",
active: 0,
},
{
id: 13,
content: "Cockroaches",
active: 0,
},
],
],
data_source: [],
}
},
computed: {
itemList: {
get() {
return this.data_source.filter((item) => item.active)
},
set(newValue) {
//this.itemList = newValue; <--
}
}
},
methods: {
changeDatasource: function(id) {
//this.itemList = [] <--
this.data_source = this.data_sets[id];
}
}
}
</script>
<style scoped>
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
When clicking on buttons to choose a data set, you can see the transition is not okay: old items still present when the new ones come in. The expected order should be: old items disappears, then new items come in.
It's very likely because itemList is replaced as a whole at a time. So I've tried to:
- Empty
itemList= [], - Continue to make the changes. (the commented part in the snippet)
RangeError: Maximum call stack size exceeded
Guess it bounds to some kind of infinite loop, at this point I'm completely pointless.
I've also messed around with transition mode, it isn't better.
My question is there any way to apply transition to list as a whole like this?
Solution 1:[1]
Solved it by working around with setTimeout and setInterval and changed from computed propery to watch.
Content shifting is there but a little CSS and JavaScript manipulation will fix it. Not the best solution but by now that's what I can think of.
<template>
<div>
<ul>
<transition-group name="list">
<li v-for="item in itemList" :key="item.id">
{{item.content}}
</li>
</transition-group>
</ul>
</div>
<button @click="changeDatasource(0)">
Dataset 1
</button>
<button @click="changeDatasource(1)">
Dataset 2
</button>
<button @click="changeDatasource(2)">
Dataset 3
</button>
</template>
<script>
export default {
data() {
return {
data_sets: [
[{
id: 1,
content: "Frog",
active: 1,
},
{
id: 2,
content: "Elephant",
active: 0,
},
{
id: 3,
content: "Racoon",
active: 1,
},
{
id: 8,
content: "Cheetah",
active: 1,
},
],
[{
id: 4,
content: "Rooster",
active: 1,
},
{
id: 5,
content: "Cow",
active: 1,
},
{
id: 6,
content: "Cat",
active: 1,
},
{
id: 7,
content: "Dog",
active: 0,
},
],
[{
id: 10,
content: "Lion",
active: 1,
},
{
id: 11,
content: "Shark",
active: 1,
},
{
id: 12,
content: "Bee",
active: 0,
},
{
id: 13,
content: "Cockroaches",
active: 0,
},
],
],
data_source: [],
itemList: [],
}
},
methods: {
changeDatasource: function(id) {
//this.itemList = [] <--
this.data_source = this.data_sets[id];
}
},
watch: {
data_source: function(newValue, oldValue) {
let initialLength = this.itemList.length;
if (initialLength > 0) {
this.itemList = [];
}
let dataLength = newValue.length;
let interval = 200;
let i = 0;
let timer = setInterval(() => {
setTimeout(() => {
if (typeof newValue[i - 1] != 'undefined') {
this.itemList.push(newValue[i - 1])
}
}, interval)
if (i === dataLength - 1) {
clearInterval(timer);
}
i++;
}, interval)
}
}
}
</script>
<style scoped>
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Huy Ph?m |
