问题
做项目的时候有一个需求就是,当点击新建的时候就往树结构中添加一个主题,如有没有选中节点,就在根节点最后面push一个,如果有选中的节点,要先看是父节点还是子节点,如果是父节点,就在父节点的子节点最后push一个节点,如果选中的是子节点,就在该子节点的后面添加一个同级的子节点
<el-tree
ref="treeRef"
:default-expanded-keys="[1]" //默认展开id=1的节点
:data="dataSource" //树的数据
node-key="id" //每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
show-checkbox //展示复选框
check-strictly //父子节点不关联
:expand-on-click-node="false" //只有在点击复选框时才会选中节点
>
<template #default="{ node, data }">
<div class="custom-tree-node">
<span class="icon-box">
<i
class="iconfont icon-a-tubiao5"
v-if="data.children || (data.children && data.showInputBox)"
></i>
<i class="iconfont icon-yuandianxiao" v-else></i>
</span>
<span>{{ node.label }}</span>
<!--input输入-->
<div class="input-box" v-if="ifAddInputVisible(data)">
<el-input
clearable
placeholder="请输入文件名"
v-model="topic"
></el-input>
<div class="input-icon">
<i
class="iconfont icon-cuowu"
@click="inputCanel(data, node)"
></i>
<i
class="iconfont icon-duihao"
@click="inputConfirm(data, node)"
></i>
</div>
</div>
</div>
</template>
</el-tree>
解决方案
- 先看有没有选中的节点(在el-tree中有一个方法,getCheckedNodes() 返回当前选中节点的数据 )
- 看选中的是父节点还是子节点 (利用getCheckedNodes() 方法,判断是否有children,如果有就是父节点,如果没有就是子节点)
- 如果的是父节点,直接在后面push
- 如果的是子节点,就要先找到子节点的父节点,然后找到当前子节点在父节点中的位置,然后在这个位置后面添加一个新的子节点
代码
const addTheme = () => {
// 获取当前选中节点的数据
const currentNodeData = treeRef.value.getCheckedNodes();
if (currentNodeData.length > 0) {
//有选中的节点
const currentNode = currentNodeData[0];
const parentNode = findParentNode(dataSource.value, currentNode.id);
if (currentNode.children) {
//选中的是父节点
// 直接向 children 数组添加新节点
parentNode.children.push({
label: "",
showInputBox: true,
id: generateUniqueId(),//给节点添加一个唯一的id
});
//展开选中的父节点
const newNode = treeRef.value.getNode(currentNode.id);
newNode.expanded = true;
} else {
//选中的是子节点
// 在父节点的 children 数组中插入新节点
const index = parentNode.children.findIndex(
(node) => node === currentNode
);
if (index > -1) {
parentNode.children.splice(index + 1, 0, {
label: "",
showInputBox: true,
id: generateUniqueId(),
});
}
}
} else {
// 没有选中节点时,在根节点中添加新节点
dataSource.value.push({
label: "",
showInputBox: true,
children: [],
id: generateUniqueId(),
});
}
};
利用递归获取到当前节点的父节点
//获取选中节点的父节点
const findParentNode = (nodes, targetNodeId) => {
for (const node of nodes) {
if (node.id === targetNodeId) {
return node; // 当前节点是父节点,直接返回
}
if (node.children) {
const childNode = findParentNode(node.children, targetNodeId);
if (childNode) {
return node; // 当前节点是子节点,返回当前节点的父节点
}
}
}
return null; // 没有找到点击节点的父节点
};
输入框后面的 x 和✓
const inputConfirm = (node) => {
if (topic.value.trim() === "") {
// 输入为空时给出提示
ElMessage.warning("请输入节点名称");
return;
}
node.showInputBox = false; // 隐藏输入框
node.label = topic.value; // 设置节点名称
topic.value = ""; // 清空输入框内容
};
//取消新建
const inputCanel = (data, node) => {
// 取消输入,移除节点
const parentNode = node.parent;
const childrenArray = parentNode.data.children || parentNode.data; // 获取父节点的子节点数组
const index = childrenArray.indexOf(data); // 查找要删除节点的索引
if (index > -1) {
childrenArray.splice(index, 1); // 从数组中移除节点
}
topic.value = ""; // 清空输入框内容
};