原文地址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(); }
以上