最近的一个需求是图片拖拽排序功能,看到拖拽首先想到的“搬运”一下react-beautiful-dnd,毕竟在trello和jira里面已经见识过了,做的很漂亮。唯一的问题就是功能和体积都远远超过了我们的需求,所以自己实现更合适。

这里是Atlassian的团队分享的关于dnd开发的要点,可见交互良好的拖拽组件考虑的点还是很多的,而要实现这些特性,原生的drag事件其实是不够的,需要js全程模拟一遍,这个时间成本也是很高的,所以我的决定是简陋一点还是用原生拖拽事件吧。。。

实现

拖拽排序组件整体思路是,组件state的list数组管理需要排序的item的顺序,利用拖拽修改state。思路和实现很简单,我这里其实只是想说下实现过程的各种细节问题。

  1. 容器要阻止dragenter dragover drop默认行为,即调用preventDefault,drop还需要阻止冒泡。因为浏览器对拖拽有很多默认行为,比如Firefox下拖拽图片会在新的标签页面打开图片。

  2. 即使没有数据也最好随便设给dataTransfer设一个值,否则safari下会有兼容性问题。

  3. dragenter事件是以鼠标进入为基准触发的,这个特点其实在交互体验上不是很好,react-beautiful-dnd由于是自己实现,他们选择了根据拖拽元素的中心是否进入元素来判断。

  4. 跟随鼠标的被拖动元素的样式想要定制是非常困难的,这也是绝大多数库选择自己实现的原因。

其实整个移动的js代码就一行:list.splice(index, 0, list.splice(movingIndex, 1)[0]); movingIndex是被移动的元素。剩下的代码全部都是在处理兼容性和样式。。。