我相信使用 vanilla Dragula 库而不是 Vue-Dragula 包装器会更容易。这将使您免于很多麻烦,还可以减小包大小。
我是这样使用的:
import dragula from 'dragula'
data()
{
return {
stages: { // we have 5 lists - items can be dragged between any 2 of them
LEAD_IN: [],
HOMEOWNER_ADDED: [],
PROPOSAL_GENERATED: [],
WON: [],
LOST: [],
},
drake: null,
}
},
mounted()
{
// IMPORTANT !!! prevent default image dragging for IE which interferes badly with Dragula
document.ondragstart = function () {
return false
}
this.drake = dragula({
isContainer: this.dragContainer,
moves: this.dragMoves,
accepts: this.dragAccept,
mirrorContainer: document.getElementById('app'), //eslint-disable-line
})
this.drake.on('drop', this.drakeDrop)
this.drake.on('drag', this.drakeStart)
this.drake.on('over', this.drakeOver)
this.drake.on('out', this.drakeStop)
this.drake.on('cancel', this.drakeStop)
},
methods:
{
dragContainer(el) {
// defines containers for draggable items
return 'kind' in el.dataset
},
dragMoves(el, source, handle, sibling) {
// allows dragging only by using the HANDLE
return 'move' in handle.dataset
},
dragAccept(el, target, source, sibling) {
// only containers can accept draggable items
return 'kind' in target.dataset
},
drakeStart(el, source) {
// indicate which container's item we have started dragging
source.classList.add('drag_src')
},
drakeOver(el, container, source) {
source.classList.add('drag_src')
container.classList.add('drag_dst')
},
drakeStop(el, container, source) {
source.classList.remove('drag_src')
container.classList.remove('drag_dst')
},
drakeDrop(el, target, source, sibling) {
// EL was dropped into TARGET before SIBLING and originally came from SOURCE
this.drake.cancel(true) // !!! very important - we do not want Dragula to mess with the DOM as it will confuse Vue
if (source !== target) {
// update arrays
const task = this.stages[source.dataset.kind].splice(el.dataset.index, 1)[0]
const dst = this.stages[target.dataset.kind]
dst.splice(sibling ? sibling.dataset.index : dst.length, 0, task)
this.updateTask(task, target.dataset.kind)
}
},
updateTask(task, newStage) {
this.loading = true
this.$axios
.post('/houses/stages', {
lead_id: task.lead.id,
kind: newStage,
})
.then(() => {
this.loading = false
})
.catch((error) => {
this.loading = false
events.$emit(TOAST_ERROR, error.message || error)
})
},
}
每个列表的模板是
<div :data-kind="kind" class="task_list">
<div v-for="(task, idx) in list" :key="task.id" class="task_item" :data-index="idx">
<div class="flexbox">
<div class="content_move" data-move>this is the drag HANDLER</div>
<button>some action, eventually</button>
</div>
</div>
</div>
kind 属性应该(在我的特定情况下)与 this.stages 对象的属性匹配。
还有一些方便的样式
.task_item {
cursor: grabbing;
}
.task_list .task_item {
cursor: default;
}
.task_list .task_item .content_move {
cursor: move;
}
.task_list.drag_dst {
border: 1px solid green;
}
.task_list.drag_src.drag_dst {
border: 1px solid red;
}