@vdnd/v3
Version:
Easy used vue drag and drop component library.
274 lines (168 loc) • 10.4 kB
Markdown
# 简介
简单易用的拖拽放置 vue 组件库。
vdnd 只抽象出拖拽了什么以及将其放置在了哪里,而不实现具体的放置效果。
# 示例
```typescript
import { ref } from 'vue';
import { push, remove } from '@vdnd/v3';
import { useMouseDnd, MouseDnd, DndSource, DndDropzone } from '@vdnd/v3';
import type { DropEvent } from '@vdnd/v3';
const dnd = useMouseDnd<number>({
strict: true,
});
const left = ref([1, 2, 3]);
const right = ref<number[]>([]);
const onDrop = (e: DropEvent<number>) => {
if (e.source.label === 'left' && e.dropzone.label === 'right') {
push(right, remove(left, e.source.value!));
}
};
```
```html
<MouseDnd :instance="dnd" class="example" @drop="onDrop">
<div>
<DndSource v-for="(number, index) in left" :key="index" label="left" :value="index">
{{ number }}
</DndSource>
</div>
<DndDropzone label="right">
<div v-if="!right.length" class="empty">拖到这里来</div>
<div v-for="(number, index) in right" :key="index" class="right-box">{{ number }}</div>
</DndDropzone>
</MouseDnd>
```
[在线示例](http://zbd329.top/vdnd/?lang=zh-cn&index=0)
# API
## 插件
### NativeDndPlugin
注册全局组件:`NativeDnd`、`DndSource`、`DndDropzone`、`DndHandle`。
### MouseDndPlugin
注册全局组件:`MouseDnd`、`DndSource`、`DndDropzone`、`DndHandle`。
### TouchDndPlugin
注册全局组件:`TouchDnd`、`DndSource`、`DndDropzone`、`DndHandle`。
## 组件
### DndProvider
`DndProvider` 用于渲染**拖放容器**:只有来自该容器内的拖放(拖拽放置)交互才会被 `DndProvider` 感知。
vdnd 提供了 `NativeDnd`、`MouseDnd` 和 `TouchDnd` 三类 `DndProvider`,它们使用不同的事件描述拖放交互,例如:
- `NativeDnd` 将 `dragstart` 事件的触发视为交互的开始;
- `MouseDnd` 将 `mousedown` 和 `mousemove` 事件的接连触发视为交互的开始;
- `TouchDnd` 将 `touchstart` 和 `touchmove` 事件的接连触发视为交互的开始。
#### 属性
| 名称 | 类型 | 说明 | 是否必选 | 默认值 |
| -------- | ------ | ------------------------------------------- | -------- | ------ |
| tag | string | 渲染**拖放容器**所使用的 html 标签 | 否 | 'div' |
| instance | object | [拖放交互实例.md](./docs/zh-cn/instance.md) | 是 | |
#### 插槽
| 名称 | 说明 | 参数 | 后备内容 |
| ------- | -------------------- | ---- | -------- |
| default | **拖放容器**的子节点 | 无 | 空 |
#### 事件
| 名称 | 说明 |
| ------------ | ------------------------------ |
| drag | `API#DndSource` |
| drag:start | `API#DndSource` |
| drag:prevent | `API#DndSource` |
| drag:enter | `API#DndDropzone` |
| drag:over | `API#DndDropzone` |
| drag:leave | `API#DndDropzone` |
| drop | `API#DndDropzone` |
| drag:end | `API#DndDropzone` |
| initialized | `DndProvider` 初始化完成后触发 |
更多信息请参考[拖放交互事件.md](./docs/zh-cn/event.md)。
#### 组件实例
`DndProvider` 不使用 `expose` 暴露任何内容。
### DndSource
`DndSource` 用于渲染**源**:只有尝试拖拽**拖放容器**中的**源**时,`DndProvider` 才能感知到拖拽的发生。
#### 属性
| 名称 | 类型 | 说明 | 是否必选 | 默认值 |
| --------- | ------- | ------------------------------------------------ | -------- | ------------------------------------- |
| tag | string | 渲染**源**所使用的 html 标签 | 否 | 'div' |
| label | string | 为**源**绑定一个标签,一般用于分组 | 否 | |
| value | any | 为**源**绑定一个值,在某个组内,该值通常是唯一的 | 否 | |
| draggable | boolean | 是否允许拖拽 | 否 | true |
| dropzone | boolean | 是否同时作为**放置区域** | 否 | false |
| droppable | boolean | 是否允许放置 | 否 | false;true,当 `dropzone` 为 true 时 |
当我们尝试拖拽一个可拖拽的**源**时,拖放交互开始,`DndProvider` 触发 `drag:start` 事件,并将该**源**作为**当前拖拽源**。反之,拖放交互被阻止,`DndProvider` 触发 `drag:prevent` 事件。拖放交互开始后,`DndProvider` 将会定时触发 `drag` 事件。
`DndProvider` 触发事件时,会将相关的**源**作为参数,并支持访问**源**的属性,例如 `label` 和 `value`:它们可以帮助我们快速识别出**源**的身份,并以此决定后续的操作。
> `label` 属性只是起到标记作用,vdnd 内部并没有任何关于分组的逻辑。
**源**可以同时作为**放置区域**,这会带来更多可能性。在后面,我们将了解到**放置区域**。
#### 插槽
| 名称 | 说明 | 参数 | 后备内容 |
| ------- | -------------- | ---- | -------- |
| default | **源**的子节点 | 无 | 空 |
#### 事件
`DndSource` 不触发任何事件。
#### 组件实例
`DndSource` 不使用 `expose` 暴露任何内容。
### DndDropzone
`DndDropzone` 用于渲染**放置区域**:一般来说,只有当我们在**放置区域**上结束拖放交互时,才可能产生实际的放置效果,例如将**当前拖拽源**移动到交互结束时所在的**放置区域**中。
#### 属性
| 名称 | 类型 | 说明 | 是否必选 | 默认值 |
| --------- | ------- | ------------------------------------------------------ | -------- | ------ |
| tag | string | 渲染**放置区域**所使用的 html 标签 | 否 | 'div' |
| label | string | 为**放置区域**绑定一个标签,一般用于分组 | 否 | |
| value | any | 为**放置区域**绑定一个值,在某个组内,该值通常是唯一的 | 否 | |
| droppable | boolean | 是否允许放置 | 否 | true |
在拖放交互开始后,当我们使用某种指向设备(例如鼠标)指向某个**放置区域**时,`DndProvider` 将会触发 `drag:enter` 事件,并将该**放置区域**作为**当前选择放置区域**。当我们取消指向**当前选择放置区域**时,`DndProvider` 将会触发 `drag:leave` 事件。
在拖放交互进行中时,如果**当前选择放置区域**存在,`DndProvider` 将会定时触发 `drag:over` 事件。
在拖放交互结束时,如果**当前选择放置区域**不存在,`DndProvider` 将只会触发 `drag:end` 事件。否则,`DndProvider` 将会根据**当前选择放置区域**的可放置与否决定触发 `drop` 或 `drag:leave` 事件,并随后触发 `drag:end` 事件。
#### 插槽
| 名称 | 说明 | 参数 | 后备内容 |
| ------- | -------------------- | ---- | -------- |
| default | **放置区域**的子节点 | 无 | 空 |
#### 事件
`DndDropzone` 不触发任何事件。
#### 组件实例
`DndDropzone` 不使用 `expose` 暴露任何内容。
### DndHandle
`DndHandle` 用于渲染**拖拽触发器**。如果某个**源**中包含**拖拽触发器**,那么只有当我们尝试拖拽该**源**中的**拖拽触发器**时,`DndProvider` 才能感知到我们正在尝试拖拽该**源**,并随后触发 `drag:start` 或 `drag:prevent` 事件。
#### 属性
| 名称 | 类型 | 说明 | 是否必选 | 默认值 |
| ---- | ------ | ------------------------------------ | -------- | ------ |
| tag | string | 渲染**拖拽触发器**所使用的 html 标签 | 否 | 'div' |
#### 插槽
| 名称 | 说明 | 参数 | 后备内容 |
| ------- | ---------------------- | ---- | -------- |
| default | **拖拽触发器**的子节点 | 无 | 空 |
#### 事件
`DndHandle` 不触发任何事件。
#### 组件实例
`DndHandle` 不使用 `expose` 暴露任何内容。
## 组合式函数
### useDnd
创建一个[拖放交互实例](./docs/zh-cn/instance.md),通过选项 `type` 区分实例种类。
### useNativeDnd
创建一个 `NativeDnd` 专用的[拖放交互实例](./docs/zh-cn/instance.md)。
### useMouseDnd
创建一个 `MouseDnd` 专用的[拖放交互实例](./docs/zh-cn/instance.md)。
### useTouchDnd
创建一个 `TouchDnd` 专用的[拖放交互实例](./docs/zh-cn/instance.md)。
## 数组工具函数
vdnd 提供了一组更新响应式数组的工具函数,在实现具体的放置效果时会十分有帮助。
### unshift
在数组头部插入一个元素。
### shift
移除数组中的第一个元素。
### push
在数组尾部插入一个元素。
### pop
移除数组中的最后一个元素。
### splice
移除数组中的多个元素,并可以在移除的位置上插入多个元素。
### find
返回第一个满足条件的元素(从左向右查找)。
### findLast
返回第一个满足条件的元素(从右向左查找)。
### findIndex
返回第一个满足条件的元素的索引(从左向右查找)。
### findLastIndex
返回第一个满足条件的元素的索引(从右向左查找)。
### swap
- 交换两个数组中的元素。
- 交换一个数组中的两个元素。
### remove
移除数组中满足条件的第一个元素。
### insert
在数组某个位置的前或后插入多个元素。
# 感谢
[@shopify/draggable](https://www.npmjs.com/package/@shopify/draggable)为 vdnd 带来了灵感。