正在加载演示…
<script setup lang="ts">
import { ref } from 'vue';
import { DnDProvider, closestCenter, closestCorners, pointerFirst, pointerWithin, rectIntersection } from '@vue-dnd-kit/core';
import ModifierLab from './ModifierLab.vue';
// Collision detection is the provider's: it picks the target, here one of the two pads.
const COLLISIONS = { pointerFirst, pointerWithin, rectIntersection, closestCenter, closestCorners };
const collision = ref<keyof typeof COLLISIONS>('pointerFirst');
</script>
<template>
<DnDProvider :collision="COLLISIONS[collision]">
<div class="demo">
<code class="call"><DnDProvider :collision="{{ collision }}"></code>
<div class="collisions" role="radiogroup" aria-label="collision">
<label v-for="name in Object.keys(COLLISIONS)" :key="name" :class="{ on: collision === name }">
<input v-model="collision" type="radio" :value="name" />
{{ name }}
</label>
</div>
<ModifierLab />
</div>
</DnDProvider>
</template>
<style scoped>
.demo {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.collisions {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 2px;
max-width: 100%;
padding: 3px;
border-radius: 9px;
background: color-mix(in srgb, currentColor 7%, transparent);
}
.call {
font: 11px/1.4 ui-monospace, Menlo, Consolas, monospace;
color: #42b883;
}
label {
padding: 4px 8px;
border-radius: 6px;
font: 11px/1.3 ui-monospace, Menlo, Consolas, monospace;
cursor: pointer;
}
label.on {
background: Canvas;
box-shadow: 0 1px 3px rgb(0 0 0 / 0.25);
font-weight: 600;
}
label:has(input:focus-visible) {
outline: 2px solid #42b883;
}
input {
position: absolute;
opacity: 0;
pointer-events: none;
}
</style>修饰器
import { restrictToParent, snapToGrid } from '@vue-dnd-kit/core';
makeSortableList(list, { items, modifiers: [restrictToParent] });
makeDragArea(board, { modifiers: [snapToGrid({ x: 24, y: 24, smooth: true })] });
修饰器接收拖拽的偏移量,并返回一个新的偏移量。它们按顺序运行:provider 的 modifiers、拖拽区域的、可拖拽元素自己的(或其列表的),然后是区域的边界(restrictToArea),最后是 axis 锁定。参见轴、边界与网格。
Modifier只在垂直方向移动:水平方向上,无论页面如何滚动,它都跟随开始时所在的内容(containerShift)。axis: 'y' 选项做的是同样的事,并且最后应用。
Modifier只在水平方向移动:垂直方向上,无论页面如何滚动,它都跟随开始时所在的内容(containerShift)。axis: 'x' 选项做的是同样的事,并且最后应用。
Modifier把浮层限制在窗口内。
Modifier把浮层限制在拖拽开始时所在的容器内:可排序列表(而不是它的 DOM 父元素),对于普通的可拖拽元素则是父元素。
(target: MaybeElementRef) => Modifier把浮层限制在某个元素内:元素本身、ref 或 getter。
Modifier把浮层限制在被拖拽元素的第一个可滚动祖先元素内。
(size: number | SnapToGridOptions) => Modifier把浮层吸附到网格上最近的单元格:数字表示正方形单元格的尺寸;选项可以分别设置每个轴、网格的起点,以及在单元格之间的滑动(SnapToGridOptions)。
Modifier让浮层中心对准指针,而不是保持抓取时的偏移。
snapToGrid 的选项。
改变被拖拽项去往的位置:接收拖拽的偏移量(transform)并返回新的偏移量。
type Modifier = (args: ModifierArgs) => Coordinates修饰器在拖拽每次移动时收到的参数。
Coordinates相对拖拽起点的偏移量,已经过前面的修饰器处理。
Active这次拖拽。
Rect拖拽开始时被拖拽元素的矩形。
Rect假如浮层盒子按 transform 移动、并保持当前尺寸时的矩形。使用 overlayFit: 'slot' 时,盒子会围绕指针调整尺寸,所以它并不总是等于按 transform 移动后的 activeRect。
Coordinates拖拽开始时的指针位置。
Rect | null被拖拽项所在的可排序列表容器(或父元素)的当前位置(它会跟随滚动)。
Coordinates拖拽开始时所在的内容自开始以来在屏幕上移动了多远:容器本身移动了(页面或它外层的容器滚动了、布局发生了偏移),以及它的内容在容器内滚动了。轴锁定把另一个轴保持在这个偏移上,所以拖拽会停留在该内容中它所在的那一行或那一列。
Rect窗口(视口)的矩形。
Over | null拖拽下方的放置目标,以最近一次找到的为准;不在任何目标上方时为 null。
碰撞检测
import { closestCorners } from '@vue-dnd-kit/core';
<DnDProvider :collision="closestCorners" />
provider 的 collision 负责选出目标;最佳候选排在最前。
CollisionDetection默认:指针下方的目标,否则是浮层重叠的目标。
CollisionDetection指针下方的目标,来自命中测试:遵循 z-order、浮层和 shadow root。
CollisionDetection与浮层重叠的目标:先比优先级,再比嵌套深度,最后比交并比(intersection over union)。
CollisionDetection所有目标,按中心之间的距离排序。
CollisionDetection所有目标,按各角之间的距离之和排序(适合堆叠的目标,例如看板的列)。
返回候选 id,最佳的在前。
type CollisionDetection = (args: CollisionArgs) => Key[]碰撞检测在拖拽每次移动时收到的参数。
Coordinates视口坐标中的指针位置,已应用修饰器。
Rect | null被拖拽的盒子(浮层,或在 overlay: false 时元素本身)被拖到的位置上的矩形。
CollisionCandidate[]拖拽可能去往的每个放置目标,无论它的 accept 规则是否接受这次拖拽。
Key[]通过命中测试得到的指针下方的放置目标(遵循 z 轴顺序和 shadow root),最佳的在前。