文档/API

动画

动画的选项和钩子——排序、放置,以及非拖拽引起的变化。

编辑此页

本页由 AI 翻译,可能存在不准确之处。 阅读英文原文

provider 的 animation(排序时的布局移动)、dropAnimation(浮层落位)和 animateChanges(非拖拽引起的数据变化)接受 false、选项,或你自己的函数——用于 GSAP 或 motion。列表和树可以覆盖 animation 和 animateChanges;可拖拽元素、项和列表可以带上自己的 dropAnimation,放置目标则可以带上 overDropAnimation。参见动画。

<DnDProvider :animation="{ duration: 180, easing: 'ease-out' }" :drop-animation="false" />

下面的每条泳道都是一个独立的 provider,它的 animation、dropAnimation 和 animateChanges(后者在 move 中接受函数)都使用同一种取值形式。

Live

正在加载演示…

<script setup lang="ts">
import { ref } from 'vue';
import { DnDProvider, type AutoAnimation, type DropAnimation, type LayoutAnimation } from '@vue-dnd-kit/core';
import AnimLane from './AnimLane.vue';
import { tiltDrop, tiltMove } from './tilt';

const SLOW = { duration: 700, easing: 'ease-in-out' };

// One shape per lane, for all three options: sorting, the drop, and changes no drag made.
const lanes: { label: string; animation: LayoutAnimation; dropAnimation: DropAnimation; animateChanges: AutoAnimation }[] = [
  { label: 'true', animation: true, dropAnimation: true, animateChanges: true },
  { label: 'false', animation: false, dropAnimation: false, animateChanges: false },
  { label: '{ duration: 700 }', animation: SLOW, dropAnimation: SLOW, animateChanges: SLOW },
  // `animateChanges` takes no function itself: its parts (`move`, `enter`, `leave`) do.
  { label: 'ƒ tilt', animation: tiltMove, dropAnimation: tiltDrop, animateChanges: { move: tiltMove } },
];

const letters = ['A', 'B', 'C', 'D'];
const rows = ref(lanes.map(() => letters.map((id, i) => ({ id, hue: 150 + i * 40 }))));

/** The same new order in every lane (Fisher–Yates: every order as likely): `animateChanges` plays it four ways. */
const shuffle = () => {
  const order = [...letters];
  for (let i = order.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [order[i], order[j]] = [order[j]!, order[i]!];
  }
  rows.value = rows.value.map((lane) => order.map((id) => lane.find((row) => row.id === id)!));
};
</script>

<template>
  <div class="demo">
    <code>&lt;DnDProvider :animation="shape" :drop-animation="shape" :animate-changes="shape"&gt;</code>
    <div class="lanes">
      <!-- A provider per lane: each one has its own animations. -->
      <DnDProvider
        v-for="(lane, index) in lanes"
        :key="lane.label"
        :animation="lane.animation"
        :drop-animation="lane.dropAnimation"
        :animate-changes="lane.animateChanges"
      >
        <AnimLane v-model="rows[index]!" :label="lane.label" />
      </DnDProvider>
    </div>
    <button type="button" @click="shuffle">Shuffle all</button>
  </div>
</template>

<style scoped>
.demo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

code {
  max-width: 100%;
  font: 11px/1.4 ui-monospace, Menlo, Consolas, monospace;
  text-align: center;
  opacity: 0.7;
}

button {
  padding: 6px 12px;
  border: 0;
  border-radius: 8px;
  background: #42b883;
  color: #fff;
  font: 600 12px/1 system-ui, sans-serif;
  cursor: pointer;
}

button:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.lanes {
  display: grid;
  grid-template-columns: repeat(4, 128px);
  gap: 8px;
}

@media (max-width: 560px) {
  .lanes {
    grid-template-columns: repeat(2, 128px);
  }
}
</style>

选项

动画的时间设置。省略的部分保留该动画的默认值。

number

单位为 ms。布局移动默认 200,放置默认 250;0 关闭动画。

string

CSS 缓动('ease-out'、cubic-bezier(…))。

排序

项如何移动到新位置:true(默认时间)、选项、false(直接跳过去),或一个函数——它为一个项执行从 from 到 to 的动画,并返回它的 Animation、一个在动画结束时完成的 Promise,或者不返回任何东西。

type LayoutAnimation = | boolean | AnimationOptions | ((context: LayoutAnimationContext) => Animation | Promise<unknown> | void)

布局动画函数收到的参数,针对一个移动到新位置的项。

Key

项的 key。

HTMLElement

项的元素,已经在新位置上。

Rect

变化之前的视觉矩形(正在运行的动画显示该项的位置)。

Rect

变化之后的布局矩形。

Required<AnimationOptions>

选项给出的时间设置,已填入默认值。

'drag' | 'change'

是什么移动了这个项:一次拖拽('drag':排序、放置、取消),或者非拖拽引起的数据变化('change',需开启列表的 animateChanges)。

AbortSignal

库中断动画时中止:项在动画结束前再次移动(下一个动画从它当前显示的位置开始),或者动画被关闭。返回的 Animation 会自动帮你取消。其他任何东西都要在这里停止,并立即撤销它设置的样式:紧接着就会测量布局。

boolean

设置了 prefers-reduced-motion: reduce。此时库自己的动画不会运行;你的函数总会运行,并据此做出决定(跳过,或保留一个淡入淡出)。

放置

浮层在放置时如何落位、在取消时如何飞回原处:true(默认时间)、选项、false(不飞行:它停在松开的地方),或者一个函数:把 overlay 从 from 动画到 to,并返回它的 Animation、一个在动画结束时完成的 promise,或者什么都不返回。

type DropAnimation = | boolean | AnimationOptions | ((context: DropAnimationContext) => Animation | Promise<unknown> | void)

放置动画函数收到的参数:浮层、它现在的位置和它将落到的位置。

HTMLElement

浮层盒子;它会落到当前项的位置上。在多项拖拽中,随它一起移动的其他项的克隆(默认浮层中的克隆、自定义浮层中的 DragPreview)会自行落到各自的位置上(如果这是一个自定义函数,则使用默认时间)。

Rect

拖拽结束时浮层所在的位置。

Rect | null

被放下的项的最终矩形;当它没有被渲染或不可见时为 null(浮层淡出)。

Rect | null

放到一个区域(而不是可排序列表)上之后,该项不再显示,例如它被放进了另一个项(文件夹)或回收区:此时为该区域的可见矩形。默认动画会让浮层在淡出时缩进这个区域,而不是在原地淡出。

'drop' | 'cancel'

'drop':浮层落到放置把项放到的地方。'cancel':它飞回项原来所在的地方。

Active

结束的那次拖拽。

Over | null

放置落到的目标(列表、放置区);取消时为 null。

Required<AnimationOptions>

选项给出的时间设置,已填入默认值。

boolean

设置了 prefers-reduced-motion: reduce。此时库自己的动画不会运行;你的函数总会运行,并据此做出决定(跳过,或保留一个淡入淡出)。

数据变化

为非拖拽引起的列表(或树)项的变化添加动画:项被添加、删除、移动(排序、打乱、在同一分组的列表之间移动)或过滤。默认关闭(false);true 会以默认时间为移动、进入和离开的项添加动画。拖拽保留它们自己的动画(animation、dropAnimation)。在 prefers-reduced-motion: reduce 下,默认动画不会运行;你的函数仍然会运行(并收到 reducedMotion: true)。只有可见区域附近的项才会执行动画(虚拟列表中未挂载的行会被跳过)。

type AutoAnimation = boolean | AutoAnimationOptions

分部分设置的 animateChanges:duration 和 easing 适用于所有部分;每种变化可以单独设为 true、选项(覆盖共享选项)、false,或你自己的函数。

LayoutAnimation

位置发生变化的项(默认的 FLIP,与 animation 的相同;函数会替换它)。

EnterAnimation

新出现的项。默认:在原地淡入。

LeaveAnimation

离开的项。默认:该项的副本在它原来的位置淡出,同时略微缩小。

true、选项、false(项直接出现),或一个为它执行进入动画的函数。

type EnterAnimation = | boolean | AnimationOptions | ((context: EnterAnimationContext) => Animation | Promise<unknown> | void)

在开启了 animateChanges 的列表中出现的项:新添加的,或重新显示的(过滤、展开的树节点)。

Key

项的 key。

HTMLElement

该项的元素,已经位于它的位置上。

Rect

它出现的位置(布局矩形)。

Required<AnimationOptions>

选项给出的时间设置,已填入默认值。

boolean

设置了 prefers-reduced-motion: reduce。此时库自己的动画不会运行;你的函数总会运行,并据此做出决定(跳过,或保留一个淡入淡出)。

true、选项、false(项直接消失),或一个为留在原处的副本执行离开动画的函数:返回它的 Animation 或一个 Promise,副本会在动画结束时被移除(函数什么都不返回时立即移除)。

type LeaveAnimation = | boolean | AnimationOptions | ((context: LeaveAnimationContext) => Animation | Promise<unknown> | void)

从开启了 animateChanges 的列表中离开的项:被删除的,或被隐藏的(过滤、折叠的树节点)。

Key

项的 key。

HTMLElement

该项元素的副本,显示在该项原来的位置(项本身已经不在了):在原来的父元素中绝对定位,忽略指针,并带有 data-dnd-leaving 标记。你的动画结束后,库会移除它。

Rect

该项原来所在的位置。

Required<AnimationOptions>

选项给出的时间设置,已填入默认值。

boolean

设置了 prefers-reduced-motion: reduce。此时库自己的动画不会运行;你的函数总会运行,并据此做出决定(跳过,或保留一个淡入淡出)。