https://github.com/kenberkeley/vue-drag-drop-sort-demo
Vue demo for drag drop sort (for Vue.js 2.x see https://github.com/kenberkeley/vue2-drag-and-drop-demo)
https://github.com/kenberkeley/vue-drag-drop-sort-demo
dnd drag drop vue
Last synced: 6 months ago
JSON representation
Vue demo for drag drop sort (for Vue.js 2.x see https://github.com/kenberkeley/vue2-drag-and-drop-demo)
- Host: GitHub
- URL: https://github.com/kenberkeley/vue-drag-drop-sort-demo
- Owner: kenberkeley
- License: mit
- Created: 2016-11-15T04:33:57.000Z (almost 9 years ago)
- Default Branch: master
- Last Pushed: 2018-01-10T08:15:43.000Z (over 7 years ago)
- Last Synced: 2025-04-15T04:12:40.990Z (6 months ago)
- Topics: dnd, drag, drop, vue
- Language: Vue
- Homepage:
- Size: 4.88 KB
- Stars: 40
- Watchers: 4
- Forks: 12
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
For Vue.js 2.x see https://github.com/kenberkeley/vue2-drag-and-drop-demo
***
# Vue Demo : Drag + Drop + Sort ([JS Bin](http://jsbin.com/gupebi/embed?html,js,output))
Thanks to [@bramblex](https://github.com/bramblex), the original post is [here](https://www.v2ex.com/t/300047)`TreeNode.vue` ↓↓↓ (Practical usage: [vue-datatable-component - HeaderSettings.vue](https://github.com/kenberkeley/vue-datatable-component/blob/master/src/DataTable/HeaderSettings.vue))
```vue
{{ node.name }}
export default {
name: 'tree-node', // 递归组件需指明 name
props: {
vm: { twoWay: true }, // 正在拖动的节点实例(TreeNode 组件通用,须双向绑定)
node: Object, // 节点数据,形如 { name: 'xxx', children: [] }
idx: Number // v-for 的索引,用于相邻节点的判别
},
computed: {
children () { // 为每个子节点前后都生成空节点,便于实现兄弟节点间的“插入排序”
// 举例:原本是 [N1, N2, N3]
let { children } = this.node
if (!children || !children.length) return []
let _children = []
children.forEach(child => _children.push({}, child))
_children.push({})// 最后生成 [E1, N1, E2, N2, E3, N3, E4](其中 N 表示节点,E 表示空节点)
return _children
},
isParent () { // 拖放限制 1:判断“我”是否为被拖动节点的父节点
return this === this.vm.$parent
},
isNextToMe () { // 拖放限制 2:判断“我”是否为被拖动节点的相邻节点
return this.$parent === this.vm.$parent && Math.abs(this.idx - this.vm.idx) === 1
},
isMeOrMyAncestor () { // 拖放限制 3:判断被拖动节点是否为“我”自身或“我”的祖先
var p = this
while (p) {
if (this.vm === p) return true
p = p.$parent
}
},
isAllowToDrop () { // 上述拖放限制条件的综合
return !(this.isParent || this.isNextToMe || this.isMeOrMyAncestor)
}
},
methods: {
clearBgColor () { // 清理样式
this.$el.style.backgroundColor = ''
},
handleDragStart () {
this.vm = this // 设置本组件为当前正在拖动的实例,此举将同步 sync 到所有 TreeNode 实例
this.$el.style.backgroundColor = 'silver'
},
handleDrop () {
this.clearBgColor() // 此时 this 为目的地节点,vm 才是被拖动节点
if (!this.isAllowToDrop) return// 无论如何都直接删除被拖动节点
this.vm.$parent.node.children.$remove(this.vm.node)// 情况 1:拖入空节点,成其兄弟(使用 splice 插入节点)
if (!this.node.name)
return this.$parent.node.children.splice(this.idx / 2, 0, this.vm.node)// 情况2:拖入普通节点,成为其子
if (!this.node.children) this.$set('node.children', []) // 须用 $set 引入双向绑定
this.node.children.push(this.vm.node)
},
handleDragEnter () { // 允许拖放才会显示样式
if (!this.isAllowToDrop) return
this.$el.style.backgroundColor = 'yellow'
},
handleDragLeave () {
this.clearBgColor()
},
handleDragEnd () {
this.clearBgColor()
}
}
}/* 普通节点 */
.tree-node {
display: list-item;
list-style: none;
border-left: 1px dashed gray;
}
/* 空节点 */
.tree-node.empty-node {
height: .5em;
list-style-type: none;
}
/* 层次缩进 */
.tree-node-children {
margin-left: 2em;
}```