Reputation: 1911
Recently, I read a svelte tutorial on Deferred transitions
. With few lines of code it was easy to achieve the transition as shown in GIF below.
I am curious on how to implement the same effect using Vue transitions. I read docs on Vue Transition and TransitionGroup, but I couldn't see how I could achieve same effect.
Upvotes: 1
Views: 116
Reputation: 1911
Following is my attempt to acheive the described animation using vue 3.
<script setup lang="ts">
import { ref, computed, nextTick } from 'vue'
const todos = ref([
{ title: 'Task 1', done: false },
{ title: 'Task 2', done: false },
{ title: 'Task 3', done: false },
{ title: 'Task 4', done: false },
{ title: 'Task 5', done: false }
])
const pendingList = computed(() => todos.value.filter((t) => !t.done))
const doneList = computed(() => todos.value.filter((t) => t.done))
const pendingListRef = ref<any[] | null>(null)
const doneListRef = ref<any[] | null>(null)
function pendingBeforeLeave(el: any) {
nextTick(() => {
const eleInDone = doneListRef.value?.find((e) => e.id === el.id)
const translateX = eleInDone.offsetLeft - el.offsetLeft
const translateY = eleInDone.offsetTop - el.offsetTop
el.style.transform = `translate(${translateX}px, ${translateY}px)`
})
}
function doneBeforeLeave(el: any) {
nextTick(() => {
const eleInPending = pendingListRef.value?.find((e) => e.id === el.id)
const translateX = eleInPending.offsetLeft - el.offsetLeft
const translateY = eleInPending.offsetTop - el.offsetTop
el.style.transform = `translate(${translateX}px, ${translateY}px)`
})
}
</script>
<template>
<div class="todo-container">
<div class="list">
<h1>Todo</h1>
<TransitionGroup @beforeLeave="pendingBeforeLeave" name="pending" tag="ul">
<li
class="list-item"
:id="todo.title"
ref="pendingListRef"
v-for="todo in pendingList"
:key="todo.title"
@click="todo.done = true"
>
{{ todo.title }}
</li>
</TransitionGroup>
</div>
<div class="list">
<h1>Done</h1>
<TransitionGroup @beforeLeave="doneBeforeLeave" name="done" tag="ul">
<li
class="list-item"
ref="doneListRef"
:id="todo.title"
v-for="todo in doneList"
:key="todo.title"
@click="todo.done = false"
>
{{ todo.title }}
</li>
</TransitionGroup>
</div>
</div>
</template>
<style scoped>
.list-item {
transition-property: transform, opacity;
transition-delay: 0s, 1.1s;
transition-duration: 1s, 0.1s;
transition-timing-function: ease, linear;
}
.pending-enter-from,
.done-enter-from {
opacity: 0;
}
.pending-enter-to,
.done-enter-to {
opacity: 1;
}
/* Below style defining look and feel nothing to do with animation*/
.todo-container {
display: flex;
flex-direction: row;
justify-items: self-end;
min-height: 100vh;
padding: 15px;
margin-left: auto;
margin-right: auto;
justify-content: center;
}
.list {
width: 400px;
}
.list ul li {
margin: 5px;
padding: 15px;
background: grey;
list-style: none;
cursor: pointer;
}
</style>
Here is working example: https://playcode.io/1342702
Upvotes: 0