前言
https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_Drag_and_Drop_API https://juejin.cn/post/7075918201359433758#heading-16
html5 中提供了一系列Drag and Drop 接口,主要包括四部分:DragEvent
,DataTansfer
,DataTransferItem
和DataTransferItemList
。
API
DragEvent
两种元素
- 被拖拽元素:被拖的东西
- 目标元素:放的地方
事件
| 事件 | 事件处理程序 | 事件主体 | 触发时机 | | —- | —- | —- | —- | | dragstart | ondragstart | 源元素 | 当源元素开始被拖拽。 | | drag | ondrag | 源元素 | 当源元素被拖拽(持续触发)。 | | dragend | ondragend | 源元素 | 当源元素拖拽结束(鼠标释放或按下esc键) | | dragenter | ondragenter | 目标元素 | 当被拖拽元素进入该元素。 | | dragover | ondragover | 目标元素 | 当被拖拽元素停留在该元素(持续触发)。 | | dragleave | ondragleave | 目标元素 | 当被拖拽元素离开该元素。 | | drop | ondrop | 目标元素 | 当拖拽事件在合法的目标元素上释放。 |
事件顺序
被拖拽元素:dragstart->drag->dragend
目标元素:dragenter->dragover->drop/dropleave
tips
如果某个元素同时设置了dragover
和drop
的监听,那么必须阻止dragover
的默认行为
,否则drop
将不会被触发
。
DataTransfer
就是拖放过程中对数据进行传输
其中setData
用来存放数据,getData
用来获取数据,出于安全的考量,数据只能在drop
时获取,而effectAllowed
和dropEffect
则影响鼠标展示的样式
其他两个就不说了,看mdn
实操
改变组件位置
- position :abs通过top/left等直接改变元素的位置
- css的transform属性中的translate对元素的位置进行改变
拖拽向量
DragEvent
继承自MouseEvent
,所以我们可以通过MouseEvent
接口的offsetX
属性和offsetY
属性获取鼠标现在相对于该物体的位置差
实现1.0
获取初始位置
Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有 CSS 属性的值。 私有的 CSS 属性值可以通过对象提供的 API 或通过简单地使用 CSS 属性名称进行索引来访问。 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getComputedStyle
然后根据x、y轴上向量修改 transform 属性
sourceElem.addEventListener('dragend', (e) => {
const startPosition = window.getComputedStyle(e.target).transform;
e.target.style.transform = `${startPosition} translate(${e.offsetX}px, ${e.offsetY}px)`;
}, true);
实现1.1
实际上,还需要靠考虑鼠标在元素的位置
function enableDrag(element) {
let mouseDiff = null;
element.addEventListener('dragstart', (e) => {
//初始时鼠标与元素的位置差
mouseDiff = `translate(${-e.offsetX}px, ${-e.offsetY}px)`
}, true);
element.addEventListener('dragend', (e) => {
//开始时元素的位置
const startPosition = window.getComputedStyle(e.target).transform;
//鼠标移动的位置
const mouseMove = `translate(${e.offsetX}px, ${e.offsetY}px)`;
e.target.style.transform = `${mouseDiff} ${startPosition} ${mouseMove}`;
}, true);
}
enableDrag(souceElement);
图的连线
节点用DOM,连线用SVG
一个图由nodes
和edges
两部分组成 ,数组存储, 每个node
一个唯一的id
,使用Map
去映射id与对应的positon
形如[x,y]
的关系,而edge
有源端与终端的id
,通过id
去获得对应的坐标