element-plus 树形控件 拖拽+增删改 js

<template>

<div class="department-box">

<div class="custom-tree-container">

<el-tooltip

class="box-item"

effect="dark"

content="按住鼠标即可拖动"

placement="top"

>

<el-tree

:data="dataSource"

node-key="id"

default-expand-all

:expand-on-click-node="false"

draggable

@node-drag-start="handleDragStart"

@node-drag-enter="handleDragEnter"

@node-drag-leave="handleDragLeave"

@node-drag-over="handleDragOver"

@node-drag-end="handleDragEnd"

@node-drop="handleDrop"

>

<template #default="{ node, data }">

<div class="custom-tree-node">

<span>{{ node.label }}</span>

<div class="handle-box">

<div link @click="append(data)" class="del-icon">

增加

</div>

<div

style="margin-left: 4px"

type="danger"

link

@click="handleNodeClick(node, data)"

class="del-icon"

>

编辑

</div>

<el-popconfirm

class="box-item"

title="是否删除该部门"

placement="right"

@confirm="remove(node, data)"

>

<template #reference>

<div style="margin-left: 4px" link class="del-icon">

删除

</div>

</template>

</el-popconfirm>

</div>

</div>

</template>

</el-tree>

</el-tooltip>

</div>

<div class="department-edit-box">

<el-form>

<el-form-item label="部门名称">

<el-input v-model="editData" />

</el-form-item>

</el-form>

<el-button type="primary" @click="saveEdit">保存</el-button>

</div>

</div>

</template>

<script setup>

import { ref } from 'vue';

import { ElButton, ElMessage } from 'element-plus';

let id = 1000;

// 当前编辑的节点

const currentNode = ref(null);

const editData = ref('');

const editDataId = ref('');

/**

* 处理节点点击事件

* @param {Object} node - 节点对象

* @param {Object} data - 节点数据

*/

const handleNodeClick = (node, data) => {

currentNode.value = node;

editData.value = node.label;

editDataId.value = data.id;

};

/**

* 保存编辑内容

*/

const saveEdit = () => {

if (!currentNode.value) {

ElMessage.warning('请先选择要编辑的节点');

return;

}

if (!editData.value.trim()) {

ElMessage.warning('部门名称不能为空');

return;

}

// 同时更新原始数据源中的对应节点

 findAndUpdateLabel(dataSource.value,editDataId.value,editData.value);

};

const findAndUpdateLabel = (nodes, id, newLabel) => {

for (const node of nodes) {

if (node.id === id) {

node.label = newLabel; // 修改标签

return true;

}

if (node.children && node.children.length > 0) {

if (findAndUpdateLabel(node.children, id, newLabel)) {

return true;

}

}

}

return false;

};

/**

* 处理节点开始拖拽事件

* @param {Object} node - 当前被拖拽的节点

* @param {Event} ev - 拖拽事件对象

*/

const handleDragStart = (node, ev) => {

console.log('drag start', node);

};

/**

* 处理节点进入可放置区域事件

* @param {Object} draggingNode - 当前被拖拽的节点

* @param {Object} dropNode - 进入的可放置节点

* @param {Event} ev - 拖拽事件对象

*/

const handleDragEnter = (draggingNode, dropNode, ev) => {

console.log('tree drag enter:', dropNode.label);

};

/**

* 处理节点离开可放置区域事件

* @param {Object} draggingNode - 当前被拖拽的节点

* @param {Object} dropNode - 离开的可放置节点

* @param {Event} ev - 拖拽事件对象

*/

const handleDragLeave = (draggingNode, dropNode, ev) => {

console.log('tree drag leave:', dropNode.label);

};

/**

* 处理节点在可放置区域上方移动事件

* @param {Object} draggingNode - 当前被拖拽的节点

* @param {Object} dropNode - 上方的可放置节点

* @param {Event} ev - 拖拽事件对象

*/

const handleDragOver = (draggingNode, dropNode, ev) => {

console.log('tree drag over:', dropNode.label);

};

/**

* 处理拖拽结束事件

* @param {Object} draggingNode - 当前被拖拽的节点

* @param {Object} dropNode - 放置的目标节点

* @param {string} dropType - 放置类型('before'|'after'|'inner')

* @param {Event} ev - 拖拽事件对象

*/

const handleDragEnd = (draggingNode, dropNode, dropType, ev) => {

console.log('tree drag end:', dropNode && dropNode.label, dropType);

};

/**

* 处理节点放置事件

* @param {Object} draggingNode - 当前被拖拽的节点

* @param {Object} dropNode - 放置的目标节点

* @param {string} dropType - 放置类型('before'|'after'|'inner')

* @param {Event} ev - 拖拽事件对象

*/

const handleDrop = (draggingNode, dropNode, dropType, ev) => {

console.log('tree drop:', dropNode.label, dropType);

};


 

/**

* 添加子节点

* @param {Object} data - 当前节点数据

*/

const append = (data) => {

const newChild = { id: id++, label: '新节点', children: [] };

if (!data.children) {

data.children = [];

}

data.children.push(newChild);

dataSource.value = [...dataSource.value];

};

/**

* 删除节点

* @param {Object} node - 当前节点对象

* @param {Object} data - 当前节点数据

*/

const remove = (node, data) => {

const parent = node.parent;

const children = parent.data.children || parent.data;

const index = children.findIndex((d) => d.id === data.id);

children.splice(index, 1);

dataSource.value = [...dataSource.value];

};

// 树形数据

const dataSource = ref([

{

id: 1,

label: '总部',

children: [

{

id: 10,

label: '人力资源部',

children: [

{

id: 101,

label: '招聘组',

},

{

id: 102,

label: '培训与发展组',

},

{

id: 103,

label: '薪酬福利组',

},

],

},

{

id: 11,

label: '财务部',

children: [

{

id: 111,

label: '会计组',

},

{

id: 112,

label: '审计组',

},

],

},

],

},

{

id: 2,

label: '技术研发中心',

children: [

{

id: 20,

label: '前端开发部',

children: [

{

id: 201,

label: 'Web组',

},

{

id: 202,

label: '移动端组',

},

],

},

{

id: 21,

label: '后端开发部',

},

{

id: 22,

label: '测试部',

},

{

id: 23,

label: '产品设计部',

},

],

},

{

id: 3,

label: '市场运营中心',

children: [

{

id: 30,

label: '市场营销部',

},

{

id: 31,

label: '客户服务部',

},

{

id: 32,

label: '品牌公关部',

},

],

},

{

id: 4,

label: '区域分公司',

children: [

{

id: 40,

label: '华东分公司',

children: [

{

id: 401,

label: '上海办事处',

},

{

id: 402,

label: '杭州办事处',

},

],

},

{

id: 41,

label: '华南分公司',

},

{

id: 42,

label: '华北分公司',

},

],

},

]);

</script>

<style>

.department-box {

position: relative;

padding-top: 33px;

display: flex;

justify-content: space-between;

gap: 130px;

}

.custom-tree-container {

flex: 1;

padding: 20px;

max-width: 400px;

}

.custom-tree-node {

flex: 1;

display: flex;

align-items: center;

justify-content: space-between;

font-size: 15px !important;

padding: 10px 0;

}

.custom-tree-node span {

cursor: pointer;

padding: 2px 5px;

border-radius: 3px;

}

.custom-tree-node span:hover {

background-color: #f5f5f5;

}

.handle-box {

display: flex;

align-items: center;

justify-content: center;

font-size: 13px;

}

.del-icon img {

width: 15px;

height: 15px;

}

.department-edit-box {

display: flex;

flex-direction: column;

justify-content: flex-start;

align-items: flex-start;

padding: 20px;

flex: 1;

height: 400px;

/* box-shadow: 0 0px 2px #e5e5e5; */

border-radius: 5px;

}

body .el-tree-node__content .el-tree-node__expand-icon {

box-sizing: content-box;

padding: 6px 0 !important;

}

body .el-popconfirm__icon {

display: none !important;

}

body .el-popconfirm__main {

justify-content: center;

}

body .el-popconfirm__action{

display: flex;

justify-content: center;

}

</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值