为何弃用Html5 drag Api
- 以前我也用的Drag Api写了一个draggable组件,使用起来总以为体验有点很差。
- 先来看有赞作的相似的拖拽UI组件,它引用的sortablejs库封装了Drag Api

- 一、拖拽的时候跟随鼠标的影子成为ghost,是Api自动生成的。可是因为这是一个很简洁的页面,背景全为白色在拖拽的时候其实很难看出拖到了哪里。Api虽然提供了e.dataTransfer.setDragImage(img, 0, 0)方法让咱们在去改变这个ghost,可是设置的这个img必须是HTML img element、HTML canvas element,不然它必须是一个可见的节点。简单来讲就是若是你设置的ghost不是canvas或者img元素,而是你自定义的html元素,那你必须把它append到document中。
document.getElementById("drag-with-create-add").addEventListener("dragstart", function(e) {
var crt = this.cloneNode(true);
crt.style.backgroundColor = "red";
document.body.appendChild(crt);
e.dataTransfer.setDragImage(crt, 0, 0);
}, false);
- 这种方式好像解决了拖拽不明显的问题,可是设置的ghost是默认有一个透明度的,并且你没有办法去改变这个透明度。在上面显示的这个页面里面,即便是cloneNode一个元素出来跟随鼠标也因为这个缘由有种不清晰的感受。
- 二、快速拖拽的时候元素在不停的回流和重绘

- 从上图能够看到在拖拽排序的时候dom顺序不断在变化,虽说在拖拽的时候页面已经加载完,这点开销不会有太大的影响,可是若是可以作到一次拖拽只改变一次dom结构的话固然是最好的。
- 三、示例的拖拽没有动画效果,并且ghost跟随给人的感受有种很用力才能拖动,有点费劲。这个问题并非吹毛求疵,在稍后优化后的draggable组件动画可以体现出来。
利用鼠标事件拖拽更流畅

- 优化以后的拖拽显然比示例的顺畅不少,不会有种吃力拖动的感受。

- 在拖动的过程中,不管怎么拖动,变化的只是元素的translate,并无引发dom结构的变化,而translate并不会引发回流和重绘,而是在一次拖拽结束才进行一次更新排序。拖动过程当中也能很明显地看出当前拖拽的元素。
- 关于css影响文档流回流和重绘能够参考https://docs.google.com/sprea...
优化思路
- 弃用html5的drag,改用mouse事件
- mousedown的时候clone当前点击的元素为ghost并将原来的元素visibility:hidden;visibility让原来的元素依然占据着位置,是拖拽中不改变dom的关键。
- 设置ghost的position为fixed,脱离文档流,这样不管怎么拖拽都不会影响到布局。
- 将mousemove和mouseend事件添加到window上,这样不管鼠标怎么移动ghost都流畅跟随。mousemove的时候判断ghost与其余元素的位置,只使用translate去改变,直到真正拖拽结束才进行一次排序。
- 优化后的自定义ghost能让人清晰得看到正在移动的元素。
配合vue使用的源码:https://github.com/sally2015/...,经过v-model轻松双向绑定数据列表css