Vue 两个元素之间的延迟过渡

问题描述 投票:0回答:1

最近在

Deferred transitions
上看了一篇svelte教程。使用几行代码很容易实现如下 GIF 所示的转换。

我很好奇如何使用 Vue 过渡实现相同的效果。我阅读了有关 Vue Transition 和 TransitionGroup 的文档,但看不出如何实现相同的效果。

vuejs3 css-transitions svelte vue-transitions svelte-transition
1个回答
0
投票

以下是我尝试使用 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>

这里是工作示例:https://playcode.io/1342702

© www.soinside.com 2019 - 2024. All rights reserved.