从GGEditor的一个案例看JS原生拖拽功能

ReactG6JSGGEditor

拖拽操做平时用的比较少,在最近的一个项目中使用到了,而且踩了一些坑,本文作一个简单的总结。涉及部分G6的API,不会对理解全局产生干扰。

需求概述

以下图所示,左侧为GGEditor元素面板React组件,右侧为G6画布,现须要将元素从「元素面板」中拖拽到「画布」上。要求:html

  • 拖拽时蓝色虚线框和元素面板的对应元素尺寸相同(为一矩形)
  • 蓝色虚线框跟随鼠标移动,指明当前拖拽的位置
  • 元素面板上对应元素不该发生改变

    图片描述

⚠️图中的黑色圆圈仅为录屏软件指明鼠标操做提示html5

拖拽方法总结

相较于大部分DOM操做只须要监听某一种事件,原生拖拽功能的实现一般须要监听所有或部分的下述事件:react

事件 event.target 触发时机
drag 被拖动元素 拖拽中(每几百毫秒触发一次)
dragstart 被拖动元素 刚开始拖拽
dragend 被拖动元素 拖拽结束(鼠标释放或esc
dragover 被拖动元素下方元素 拖拽到某一目标上时(每几百毫秒一次)
dragenter 被拖动元素下方元素 被拖动元素进入可释放处时
dragleave 被拖动元素下方元素 拖拽离开某一目标时
drop 被拖动元素下方元素 dragend 且在其以前触发

需求实现

实现以前,有几个踩坑点先说明:canvas

  • 不能将左侧面板的元素设置为draggable,由于原生拖拽自带阴影效果,以下图。

图片描述
很明显这不是咱们要的效果。api

  • 拖拽时的蓝色虚线框应该由G6绘制成一个canvas的元素,由于画布能够放大或缩小,这个虚线框应和实际放在画布上的元素尺寸相同而不是左侧面板的元素尺寸相同。(不了解G6的同窗自行忽略

思路

  1. 拖拽开始或鼠标落下时,建立一个和元素大小宽高相同的透明度为0的矩形shadowShape,并监听其dragmouseup事件。
  2. document上监听dragenter事件,当target为画布时,经过G6api建立一个蓝色虚线框dragShape
  3. shadowShape移动的时候,更新dragShape的位置
  4. document上监听drop事件,落在画布时,建立一个G6的节点从而完成整个拖拽添加元素的功能。
  5. ⚠️踩坑点:必需要阻止dragover的默认行为,保证drop的正常触发,参考这则问答

图片描述

总结

1 相较于上个版本的GGEditor,实现了拖拽功能的连续性。以前,鼠标即便保持按下,一旦移出画布,就终止了本次的拖拽过程。less

图片描述
上个版本的GGEditor优化

2 待优化点:spa

  • 因为蓝色虚线框是G6画布上的元素,可以根据G6的缩放比例自动调整大小,因此在其余地方的拖拽过程不易作出相似的虚线框,体验上有间断感
  • 当前代码在一个react组件里操做了大量的原生事件监听,不够React,考虑以后直接开发一个新的组件,使用React的合成事件来重写。
相关文章
相关标签/搜索