Issue
I'm struggling to prevent triggering a transition after switching a tab.
Example
const { createApp, reactive, ref } = Vue;
const app = createApp({
setup() {
// switch tabs to see the side effects
const currentTabIdx = ref(0);
const listItems = ref([
[
{ name: 'John', id: 1 },
{ name: 'Joao', id: 2 },
{ name: 'Jean', id: 3 },
{ name: 'Gerard', id: 4 },
],
[
{ name: 'Max', id: 1 },
{ name: 'Moritz', id: 2 },
{ name: 'Foo', id: 3 },
{ name: 'Mo', id: 4 },
],
])
function shuffleList() {
listItems.value[currentTabIdx.value] = listItems.value[currentTabIdx.value].sort(() => Math.random() - 0.5);
}
return {
currentTabIdx,
listItems,
shuffleList
}
}
});
app.component('list-component', {
props: ['items'],
template: `
<ol>
<transition-group>
<li
v-for="(effect, index) in items"
:key="effect"
>
<div class="header">
<h5>{{ effect.name }}</h5>
</div>
</li>
</transition-group>
</ol>
`,
});
app.mount("#app");
li {
transition: 0.5s;
}
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s;
}
.v-leave-active {
position: absolute;
}
.v-enter,
.v-leave-to {
opacity: 0;
}
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<button @click="currentTabIdx=0">Tab 1</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
<button @click="currentTabIdx=1">Tab 2</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
| <button @click="shuffleList">Shuffle</button>
<list-component :items="listItems[currentTabIdx]"></list-component>
</div>
Problem
The child component with the list and transition-group triggers side effects on tab navigation.
Tried
I have tried to disable the transition on the body with * { transition: none !important; }
but than the list duplicates for a second.
Do you have an idea how to prevent the transition group on tab switch but enable it right afterwards?
Solution
How to prevent transition on tab change?
Maybe, there's a best way than preventing it.
If you can prefere this, you need to wrap the list-component
with the keep-alive
so that that the component is not destroyed and recreated each time the tab changes. As a result, the transition effect is maintained when reordering the list.
const { createApp, reactive, ref, nextTick } = Vue;
const app = createApp({
setup() {
const currentTabIdx = ref(0);
const listItems = ref([
[
{ name: 'John', id: 1 },
{ name: 'Joao', id: 2 },
{ name: 'Jean', id: 3 },
{ name: 'Gerard', id: 4 },
],
[
{ name: 'Max', id: 1 },
{ name: 'Moritz', id: 2 },
{ name: 'Foo', id: 3 },
{ name: 'Mo', id: 4 },
],
])
function shuffleList() {
listItems.value[currentTabIdx.value] = listItems.value[currentTabIdx.value].sort(() => Math.random() - 0.5);
}
nextTick(() => {
shuffleList();
});
return {
currentTabIdx,
listItems,
shuffleList
}
}
});
app.component('list-component', {
props: ['items'],
template: `
<ol>
<transition-group name="list" tag="ol" mode="out-in">
<li
v-for="(effect, index) in items"
:key="effect.id"
>
<div class="header">
<h5>{{ effect.name }}</h5>
</div>
</li>
</transition-group>
</ol>
`,
});
app.mount("#app");
li {
transition: 0.5s;
}
.list-enter-active,
.list-leave-active {
transition: opacity 0.5s;
}
.list-leave-active {
position: absolute;
}
.list-enter,
.list-leave-to {
opacity: 0;
}
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<button @click="currentTabIdx=0">Tab 1</button>
<button @click="currentTabIdx=1">Tab 2</button>
<button @click="shuffleList">Shuffle</button>
<keep-alive>
<component :is="'list-component'" :items="listItems[currentTabIdx]"></component>
</keep-alive>
</div>
I use also the nextTick
here to delay the call to shuffleList
until the next DOM update cycle so that the transition-group
applies the transition when the list is rendered.
Edit
the transition should stop between tabs, but within the list the transition should be applied.
const { createApp, reactive, ref } = Vue;
const app = createApp({
setup() {
const currentTabIdx = ref(0);
const listItems = ref([
[
{ name: 'John', id: 1 },
{ name: 'Joao', id: 2 },
{ name: 'Jean', id: 3 },
{ name: 'Gerard', id: 4 },
],
[
{ name: 'Max', id: 1 },
{ name: 'Moritz', id: 2 },
{ name: 'Foo', id: 3 },
{ name: 'Mo', id: 4 },
],
])
function shuffleList() {
listItems.value[currentTabIdx.value] = listItems.value[currentTabIdx.value].sort(() => Math.random() - 0.5);
}
return {
currentTabIdx,
listItems,
shuffleList
}
}
});
app.component('list-component', {
props: ['items'],
template: `
<ol>
<transition-group>
<li
v-for="(effect, index) in items"
:key="effect"
>
<div class="header">
<h5>{{ effect.name }}</h5>
</div>
</li>
</transition-group>
</ol>
`,
});
app.mount("#app");
li {
transition: 0.5s;
}
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s;
}
.v-leave-active {
position: absolute;
}
.v-enter,
.v-leave-to {
opacity: 0;
}
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<button @click="currentTabIdx=0">Tab 1</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
<button @click="currentTabIdx=1">Tab 2</button> <!-- SWITCH TABS TO SEE SIDE EFFECTS -->
| <button @click="shuffleList">Shuffle</button>
<list-component v-show="currentTabIdx === 0" :items="listItems[0]"></list-component>
<list-component v-show="currentTabIdx === 1" :items="listItems[1]"></list-component>
</div>
Here, the v-show
is used to control the visibility of the list-component
. When the currentTabIdx
changes, only the display
of the list component is toggled, and no transition is triggered.
Answered By - Keyboard Corporation
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.