el-tree树形实现鼠标拖拽,以及通过点击上下移按钮实现tree节点上下移动
1.业务需求:
- vue项目开发需求是:使用el-tree组件实现树形鼠标拖拽功能,并且在每一个树形节点的后面增加上移和下移的按钮,通过点击按钮实现节点上下移动。
2.解决方案:
-
el-tree组件使用HTML如下(我使用的这种是可以自定义树形节点内容的写法):
-
<el-tree ref="menutree" :data="treeData" node-key="sysResourcesId" :default-expand-all="false" @node-drag-start="handleDragStart" @node-drag-enter="handleDragEnter" @node-drag-leave="handleDragLeave" @node-drag-over="handleDragOver" @node-drag-end="handleDragEnd" @node-drop="handleDrop" draggable :expand-on-click-node="false" v-loading="loading" :props="defaultProps" :allow-drop="allowDrop" :allow-drag="allowDrag"> <template slot-scope="{ node, data}"> <div class="menuRowBox"> <div :id="data.sysResourcesId" style="font-size:15px;" @dblclick="workUpdate(node,data)"> <i style="padding-right: 3px" :class="'iconfont '+ data.icon"></i> {{data.resourcesName}} </div> <div class="upBox"> <el-button size="mini" type="text" plain icon="el-icon-top" @click="menuMoveF(node,data,'up')">上移</el-button> <el-button size="mini" type="text" plain icon="el-icon-bottom" @click="menuMoveF(node,data,'down')">下移</el-button> </div> </div> </template> </el-tree>
-
第一步,el-tree组件实现树形鼠标拖拽的功能其实是比较好实现的,el-tree组件自带有相关的方法与属性,调用即可实现,js 相关函数如下(到这里已经可以实现鼠标拖拽的功能了):
-
// 节点开始拖拽时触发的事件 handleDragStart(node, ev) { console.log('drag start', node,ev) this.rightPush = true this.leftPush = false ev.dataTransfer.setData("item", JSON.stringify(node.data)); }, // 拖拽进入其他节点时触发的事件 handleDragEnter(draggingNode, dropNode, ev) { console.log('tree drag enter: ', dropNode.label) }, // 拖拽离开某个节点时触发的事件 handleDragLeave(draggingNode, dropNode, ev) { console.log('tree drag leave: ', dropNode.label) }, // 在拖拽节点时触发的事件(类似浏览器的 mouseover 事件) handleDragOver(draggingNode, dropNode, ev) { console.log('tree drag over: ', dropNode.label) }, // 拖拽结束时(可能未成功)触发的事件 handleDragEnd(draggingNode, dropNode, dropType, ev) { console.log('tree drag end: ', dropNode && dropNode.label, dropType) }, // 拖拽成功完成时触发的事件 handleDrop(draggingNode, dropNode, dropType, ev) { console.log('tree drop: ',draggingNode, dropNode, dropType) }, // 拖拽时判定目标节点能否被放置。type 参数有三种情况:'prev'、'inner' 和 'next' allowDrop(draggingNode, dropNode, type) { console.log(416,draggingNode,dropNode,type) return true }, // 判断节点能否被拖拽 allowDrag(draggingNode) { return true },
-
第二步,通过点击上下移按钮实现tree节点上下移动的功能就需要自己写方法了,这里我结合了el-tree组件里面的
insertBefore
方法( 为 Tree 的一个节点的前面增加一个节点 )、insertAfter
方法( 为 Tree 的一个节点的后面增加一个节点 )、remove
方法( 删除 Tree 中的一个节点 ),insertBefore
方法与insertAfter
方法只能实现新增的功能,并不能改变原来的节点,所以需要结合删除去实现移动功能。 -
// 移动点击函数(node:当前节点,data:当前节点的data,type:区分上下移动) menuMoveF(node,data,type) { // 将变动之前的node备份 let copyNode = {...node} copyNode.previousSibling = {...node.previousSibling} copyNode.nextSibling = {...node.nextSibling} window.sessionStorage.setItem('menuNode',CircularJSON.stringify(copyNode)) let nodeData = {} if (type==='up') { // 上移 if (node.previousSibling) { // 删除原先的node this.$refs.menutree.remove(node.data) // 拿到copy的node nodeData = CircularJSON.parse(window.sessionStorage.getItem('menuNode')) // 复制该node到指定位置(参数:1. 要增加的节点的 data 2. 要增加的节点的后一个节点的 data、key 或者 node) this.$refs.menutree.insertBefore(nodeData.data,nodeData.previousSibling.data) window.sessionStorage.removeItem('menuNode') } else { this.$message.warning('该菜单已经是当前层最上级') } } else { // 下移 if (node.nextSibling) { this.$refs.menutree.remove(node.data) nodeData = CircularJSON.parse(window.sessionStorage.getItem('menuNode')) // 参数:1. 要增加的节点的 data 2. 要增加的节点的前一个节点的 data、key 或者 node this.$refs.menutree.insertAfter(nodeData.data,nodeData.nextSibling.data) window.sessionStorage.removeItem('menuNode') } else { this.$message.warning('该菜单已经是当前层最下级') } } },
-
最终效果如下(这里是上移,下移同理):