原文鏈接:兩棵el-tree的節點跨樹拖拽實現
參照這篇文章,把它做成組件,新增左側樹(可拖出)被拖節點變灰提示;
拖拽中:
拖拽后:
TreeDragComponent.vue
<template><!-- 兩棵el-tree的節點跨樹拖拽實現 --><div class="tree-drag"><!-- 左側樹(可拖出) --><el-tree:data="treeData1"ref="tree1"class="tree" node-key="id"draggabledefault-expand-all:allow-drop="returnFalse":props="defaultProps"@node-drag-start="handleDragstart"@node-drag-end="handleDragend"><!-- 使用作用域插槽自定義節點樣式 --><span slot-scope="{ node, data }" :class="{ 'custom-red': data.isHighlighted }">{{ node.label }}</span></el-tree><!-- 右側樹(可拖入) --><el-tree:data="treeData2" ref="tree2"class="tree" node-key="id"draggabledefault-expand-all:props="defaultProps":allow-drop="returnTrue"></el-tree></div>
</template><script>
export default {
name: "TreeDrag",
props:['treeData1','treeData2'],
data() {return {defaultProps: {children: 'children',label: 'name'},};
},
methods: {// (1) 手動觸發:該節點向父組件通知拖拽開始(只不過目標樹是右側樹)// 經過這個移花接木的操作,右側的樹會誤以為是自身的節點觸發了tree-node-drag-start事件,它會將被拖拽節點保存在組件內handleDragstart (node, event) {this.$refs.tree2.$emit('tree-node-drag-start', event, {node: node});},// (2) 鼠標滑過階段// 當鼠標拖拽著左側樹上的節點從右側樹上的節點劃過(也就是觸發dragover事件)時,右側樹會誤以為是在拖拽自己的節點,因此會在tree-node-drag-over事件中自動執行位置計算,所以這一階段無需我們干預。// (3)鼠標釋放階段// 盡管此時右側樹已經誤以為被拖拽的是自身節點,但被拖拽的節點此時仍然是左側樹的子組件,所以當鼠標釋放時,它只能向左側樹(即它的父組件)觸發tree-node-drag-end事件。由于左側樹不允許釋放,所以此時節點并沒有發生移動。// 為了讓右側樹收到鼠標釋放的通知,我們開始進行第二次移花接木,即把左側樹上發生的tree-node-drag-end事件以同樣的方式觸發給右側樹handleDragend (draggingNode, endNode, position, event) {//不只是做節點移動,而是拖拽復制,也就是要保留左側樹上的原節點//真正要保留原節點很難實現,所以選擇在移動后恢復左側樹上的節點// 插入一個空節點用于占位let emptyData = {id: (+new Date), children: []};this.$refs.tree1.insertBefore(emptyData, draggingNode);this.$refs.tree2.$emit('tree-node-drag-end', event);this.$nextTick(() => {// 如果是移動到了當前樹上,需要清掉空節點if (this.$refs.tree1.getNode(draggingNode.data)) {this.$refs.tree1.remove(emptyData);} else {// 如果移動到了別的樹上,需要恢復該節點,并清掉空節點let data = JSON.parse(JSON.stringify(draggingNode.data));this.createHighlightedNode(data); // 添加標記字段this.$refs.tree1.insertAfter(data, this.$refs.tree1.getNode(emptyData));this.$refs.tree1.remove(emptyData);}})},// 遞歸創建帶高亮標記的節點createHighlightedNode(data) {// 給當前節點添加 isHighlighted 屬性data.isHighlighted = true;// 檢查是否有子節點if (data.children && Array.isArray(data.children)) {// 遞歸處理每個子節點data.children.forEach(child => {this.createHighlightedNode(child);});}return data;},// 允許內部拖拽returnTrue () {// 可傳參數:draggingNode, dropNode, type// 校驗所有拖拽節點是否允許放入(如只能放入同級或特定父級)// return this.draggingNodes.every(node => // node.level <= 2 && // 限制最大層級// node.type !== 'system' // 限制類型// )return true;},// 禁止內部拖拽returnFalse () {return false;}
}
};
</script><style lang="scss" scoped>
.tree-drag {display: flex;justify-content: space-between;.tree {flex-grow: 1;.custom-red {color: #E4E4E4 !important; /* 紅色背景 */font-size: 14px !important;}}}
</style>
Parent.vue
<TreeDrag :treeData1="treeDataLeft" :treeData2="treeDataRight"></TreeDrag>
element-ui源碼中用于定義樹節點的element-ui\packages\tree\src\tree-node.vue組件
下一篇:在此基礎上加功能,el-tree拖拽事件,限制同級拖拽,獲取拖拽后節點的前后節點,同級拖拽合并父節點name且子節點加入目標節點里