JSFiddle - React, Tailwind, and code Playground
by chuangchen
HTML
<div id="app">
(后续可改成递归调用,目前只支持显示两级)
<hr>
<div style="width: 400px;">
<div :key="x.id"
v-for="x in data">
<drag-sort :id="x.id"
:has-child-node="x.children && x.children.length"
@move="moveTo">
{{ x.name }}
</drag-sort>
<!-- 后面可改成递归调用 -->
<div class="ml-8"
@move="moveTo"
v-for="item of x.children" :key="item.id">
<drag-sort :id="item.id"
:has-child-node="item.children && item.children.length"
@move="moveTo">
{{ item.name }}
</drag-sort>
</div>
</div>
</div>
</div>
<template id="dragSort">
<div draggable="true" @dragstart="dragstart" @dragleave="dragleave" @dragenter="dragenter" @dragend="dragend" @drop="drop" @dragover="dragover">
<slot />
</div>
</template>
CSS
.ml-8 {
margin-left: 32px;
}
JavaScript
Vue.component('drag-sort', {
template: '#dragSort',
props: ['id', 'hasChildNode'],
data: function() {
return {
styleMapping: {
'below': {'data-origin-border-bottom': 'borderBottom'},
'above': {'data-origin-border-top': 'borderTop'},
'inner': {'data-origin-bg-color': 'backgroundColor'},
},
styleChangeMapping: {
'below': {'borderBottom': '1px solid green'},
'above': {'borderTop': '1px solid green'},
'inner': {'backgroundColor': 'lightgray'},
}
}
},
methods: {
recoverStyle(e, removeAttrData = true) {
for (const value of Object.values(this.styleMapping)) {
for (const dataKey of Object.keys(value)) {
if (e.target.getAttribute(dataKey)) {
e.target.style[value[dataKey]] = e.target.getAttribute(dataKey)
}
if (removeAttrData) {
e.target.removeAttribute(dataKey)
}
}
}
},
checkLevel(floatValue) {
// 如果有子级:不支持直接拖拽到父级内部,请拖拽到子级的上下位置
if (this.hasChildNode) {
if (floatValue < 0.5) {
return 'above'
} else {
return 'below'
}
}
if (floatValue < 0.33) {
return 'above'
} else if (floatValue > 0.66) {
return 'below'
} else {
return 'inner'
}
},
dragstart(e) {
// dataTransfer 似乎只能在 dragstart 设置
e.dataTransfer.setData("text/plain", this.id + "")
e.target.style.opacity = '0.4'
},
dragenter(e) {
e.preventDefault()
// 【记录原始属性值】
for (const value of Object.values(this.styleMapping)) {
for (const dataKey of Object.keys(value)) {
if (!e.target.getAttribute(dataKey)) {
e.target.setAttribute(dataKey, window.getComputedStyle(e.target)[value[dataKey]]);
}
}
}
},
dragleave(e) {
// [drop的时候,被drop的元素不触发 dragleave]
this.recoverStyle(e)
},
dragend(e) {
...