由于使用的element组件,所以最初是打算采用组件提供的
{ id: 2, label: '一级 2', children: [{ id: 5, label: '二级 2-1' }
这种数据结构形式,直接在前端渲染数据,然后调用 Tree 实例的filter方法过滤树节点,添加和删除节点的方式例子中也有直接说明,然后添加一个创建根节点的方法,如下:
点击添加栏目或者添加时,都会弹出一个弹出框,将弹出框的值存储进临时currentData 中:
<el-button icon="el-icon-circle-plus-outline" type="text" @click="appendNode(0)">添加栏目</el-button>
<div class="block">
<el-input v-model="filterText" placeholder="请输入栏目名称" />
<el-tree
ref="tree"
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
:filter-node-method="filterNode"
@node-click="changeData(data)"
>
<span slot-scope="{ node, data }" class="custom-tree-node">
<span>{{ node.label }}</span>
<span>
<el-button type="text" size="mini" @click="() => appendNode(data)">添加</el-button>
<el-button type="text" size="mini" @click="() => remove(node, data)">删除</el-button>
</span>
</span>
</el-tree>
</div>
//方法
appendNode(data) {
this.AddColumnsData = {}
this.currentData = data
this.AddColumns = true
},
弹出框点击确定按钮时,执行append方法,添加一行数据
<el-button type="primary" @click="append()">确 定</el-button>
append() {
this.AddColumns = false
let id = 1000
const newChild = {
id: id++,
label: this.AddColumnsData.title,
children: []
}
if (this.currentData) {
// 点击添加时执行
if (!this.currentData.children) {
this.$set(this.currentData, 'children', [])
}
this.currentData.children.push(newChild)
} else {
// 点击添加栏目时执行
if (!this.data.children) {
this.$set(this.data, 'children', [])
}
this.data.push(newChild)
}
},
由于性能优化问题,在查询时考虑时间复杂度问题,用children遍历以及树形传递数据的问题,将后端返回数据形式修改为前端进行处理,后端数据返回pid,前端处理
source = [{
id: 1,
pid: 0,
name: 'body'
}, {
id: 2,
pid: 1,
name: 'title'
}, {
id: 3,
pid: 2,
name: 'div'
}]
// 修改为:
datas: [
{
id: 1,
pid: 0,
name: "body",
children: [
{
id: 2,
pid: 1,
name: "title",
children: [
{
id: 3,
pid: 1,
name: "div"
}
]
}
]
}
]
function toTree(data) {
let result = [];
if (!Array.isArray(data)) {
return result;
}
data.forEach(item => {
delete item.children;
});
let map = {};
data.forEach(item => {
map[item.id] = item;
});
data.forEach(item => {
let parent = map[item.pid];
let label = "";
item.label = item.name;
if (parent) {
(parent.children || (parent.children = [])).push(item);
parent.children.forEach(_item => {
_item.label = item.name;//后端字段名为name
});
} else {
result.push(item);
}
});
return result;
}
参考链接(侵删):
https://www.cnblogs.com/mengfangui/p/10494601.html
https://blog.csdn.net/susuzhe123/article/details/95353403
前端在一系列的操作后也需要将树再次转化,传到后端
jsonToArray(nodes) {
var r = [];
// console.log(nodes, "nodes");
//需要将树中的label值去掉
if (Array.isArray(nodes)) {
for (var i = 0, l = nodes.length; i < l; i++) {
r.push(nodes[i]); // 取每项数据放入一个新数组
if (
Array.isArray(nodes[i]["children"]) &&
nodes[i]["children"].length > 0
)
// 若存在children则递归调用,把数据拼接到新数组中,并且删除该children
r = r.concat(this.jsonToArray(nodes[i]["children"]));
delete nodes[i]["children"];
}
}
return r;
},
在这个过程中,需要深度拷贝,否则数据会受到干扰,不能出现正常结果。
参考链接:https://blog.csdn.net/qq_39009348/article/details/87365547
现在append方法需要在增加一个节点的时候,将pid的值绑定上去,修改方法如下:
async append() {
this.AddColumns = false;
console.log(this.currentData);
const newChild = {
label: this.AddColumnsData.title,
children: [],
createdDate: "",
groupCode: 0,
name: this.AddColumnsData.title,
orders: 0,
organizationCode: 0,
pid: this.currentData.id,
target: this.AddColumnsData.target,
updatedDate: "",
url: this.AddColumnsData.url
};
if (this.currentData) {
// 点击添加时执行
if (!this.currentData.children) {
this.$set(this.currentData, "children", []);
}
this.currentData.children.push(newChild);
await save(newChild);
} else {
// 点击添加栏目时执行
if (!this.data.children) {
this.$set(this.data, "children", []);
}
this.data.push(newChild);
await save(newChild);
}
},
这样就完成了增加子节点功能,然后需要勾选节点时,删除节点,增加以下方法:
<el-tree
ref="tree"
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
:filter-node-method="filterNode"
@node-click="changeData(data)"
@check-change="handleCheckChange"
>
</el-tree>
//勾选复选框时触发
handleCheckChange() {
let res = this.$refs.tree.getCheckedNodes();
res.forEach(item => {
this.currentTreeData += item.id + ";";
});
}
参考链接:https://blog.csdn.net/LLL_liuhui/article/details/88963616
树形结构到这里应该结束了,但是今天来测试的时候发现了一个问题
由于id是从后台获取 所以每次在新添加的节点下添加节点时需要刷新后才能添加,要不然无法获取到id值作为下一级的pid
解决方案:每次添加节点后就刷新
解决方案每次刷新用户体验感不太好,等写完再寻找更好的解决方案