原文地址vue
公司项目中本来使用vue+jQuryUI实现拖拽的效果。本来实现方式也只是要它的拖拽动态效果,阻止默认的改变dom。经过事件对象获取targetElement和toElement,就手动判断接下来的数据操做逻辑。但jQueryUI相对臃肿。就需求换个轻量级的拖拽插件。git
先推荐个vue相关的插件库
都尝试了下,选择了第一个基于sortablejs的vuedraggable。(star最多哈哈哈,配置项也最丰富)
这个插件使用方式很简单。github
注意要安装两个依赖npm install vuedraggable sortable --save
用draggable包裹被拖拽的元素,options是拖拽效果行为的相关配置,和sortable的配置基本彻底同样,start end move是相关事件。vuex
<draggable v-model="myArray" :options="{group:'people'}" @start="drag" @end="drop" :move="checkMove"> <div v-for="element in myArray">{{element.name}}</div> </draggable>
.vue or .js 文件npm
import draggable from 'vuedraggable' ... export default { components: { draggable, }, method:{ drag : function(){ ... } ... } } ...
首先是拖拽的目标元素,由于被包装后的事件对象只有index,对于更广的使用场景来讲就不太适用。例如目标元素的数据须要包装加工,或者不须要显示拖拽后的效果。vuedraggable介绍中与vuex一块儿使用的方式,并未直接修改原有数据,而进行代理。canvas
computed: { myList: { get() { return this.$store.state.myList }, set(value) { this.$store.commit('updateList', value) } } }
虽然我司项目未使用vuex,但同理改造出以下代码dom
computed: { xAxis: { get: function () { return this.dataConfig.xAxis; //return [] 此时将不会没有拖拽对象添加到对应元素中的效果。可是可获取拖拽对象绑定的数据, //在目标元素中显示canvas,图表等等数据对应的组件 }, set: function (v) { //此处可对value进行修改,好比_.uniqBy,_.filter,或者限制长度Array.slice剪切 ... this.$emit('updateDataColumn', { dataSourceCode: this.dataConfig.dataSourceCode, code: this.dataConfig.code, type: 'xAxis', columns: v }); } } }
PS:同时出现了个问题,使用的vuedraggable 2.13.1存在一个bug 拖入空元素中,当空元素的min-height大于第一个被拖拽进的元素时(必须对空元素设置min-height),会产生报错Cannot read property 'map' of undefined。可是在2.14.1版本中获得修复,相关issue可点击查看布局
第二个遇到的值得一提问题是关于HTML5原生拖拽和sortable本身实现的拖拽。默认为原生拖拽。在拖拽到空元素,容器中生成新的组件的时候,空元素的结构和位置就出现了一些问题。空元素本来放在容器中,可是设置了min-height必然会影响页面布局。因而考虑到vuedraggable拖拽添加的具体行为:拖拽通过目标空元素的时候,会先生成影子元素,除非在另外一个可落入区域drop的时候,都会添加到有影子元素的目标空元素。this
<draggable v-model="willAddToDataColumn" class="dragArea" :options="{group:'people'}" class="list-group list-group-right"> <template v-for="item in willAddDataColumn"> </template> </draggable> <draggable v-model="willAddDataColumn" class="dragArea" :options="{group:'people'}" class="list-group list-group-bottom"> <template v-for="item in willAddToDataColumn"> </template> </draggable>
分别绝对定位于容器的下,右边,且右边宽1px,下边高1px。spa
.list-group{ .sortable-chosen{display: none} //不显示影子元素。 } .list-group-right{ right: 0; position: absolute; height: 100%; width: 1px; top: 0; } .list-group-bottom{ position: absolute; height: 1px; width: 100%; bottom: 0; margin-bottom: 0; }
实现却是能实现了。可是在容器中却出现了鼠标变为不可落入状态的显示bug。因而查看sortable配置的文档。发现可经过设置forceFallback:true, fallbackClass:'draggingStyle'
来禁止使用HTML5原生拖拽。转而使用可自定义样式的拖拽。实际操做过程用又发现以前的拖拽添加的具体行为发生了改变。无法添加进去了。囧。
最终仍是找了HTML5原生拖拽来fix,在容器中添加<div class='container' @dragover="allowDrop">...</div>
allowDrop:function (ev) { ev.preventDefault(); }
以上