- 菜单表 menu_id, parent_id,order_num
- 查询给前端的 select menu_id,parent_id,order_num from menu order by parent_id,order_menu
- 前端处理
参数说明 :
data :获取的数组
id: 比如 menu_id
后面的可以不传。
示例数组(后台查出):
[
{menu_id: 1, parent_id:0 ,order_id:0},
{menu_id: 2, parent_id:0 ,order_id:1},
{menu_id: 3, parent_id:0 ,order_id:2},
{menu_id: 4, parent_id:0 ,order_id:3},
{menu_id: 5, parent_id:3 ,order_id:0},
{menu_id: 6, parent_id:4 ,order_id:0},
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]
前端 js 的一个处理函数
export function handleTree(data, id, parentId, children, rootId) {
id = id || 'id'
parentId = parentId || 'parentId'
children = children || 'children'
rootId = rootId || 0
//对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data))
//循环所有项
const treeData = cloneData.filter(father => {
let branchArr = cloneData.filter(child => {
//返回每一项的子级数组
return father[id] === child[parentId]
});
branchArr.length > 0 ? father.children = branchArr : '';
//返回第一层
return father[parentId] === rootId;
});
return treeData != '' ? treeData : data;
}
注: 我的前端比较菜,对 filter() 不了解,理了好半天才反应过来。
总结:
首先最里面的 child 过滤。 将所循环到的 节点的 子节点安排上了。
这个时候可以认为, 每个节点都是地址引用。只要有,就可以找到 N 级菜单。
最外面的 father 过滤就一个功能。干掉 父节点不是 0 的。 或者是你自己设置的根节点的值。
下面是具体示例数据的分析:
当 : menu_id ==4 的时候。把 子节点 5 加到 4 上面。
[
{menu_id: 1, parent_id:0 ,order_id:0},
{menu_id: 2, parent_id:0 ,order_id:1},
{menu_id: 3, parent_id:0 ,order_id:2 ,children: [
{menu_id: 5, parent_id:3 ,order_id:0}
]},
{menu_id: 4, parent_id:0 ,order_id:3 ,children: [
{menu_id: 6, parent_id:4 ,order_id:0}
]},
{menu_id: 5, parent_id:3 ,order_id:0},
{menu_id: 6, parent_id:4 ,order_id:0},
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]
在 menu_id == 5 没返回之前。
此时 5 已经有了子元素 7,8 。
所以从 3 可以找到 7,8 。
可以理解为地址引用。
也就是说 3 实际存放的是 5 所在的内存地址。而 5 中也是同样的存了 7,8 的地址。
[
{menu_id: 1, parent_id:0 ,order_id:0},
{menu_id: 2, parent_id:0 ,order_id:1},
{menu_id: 3, parent_id:0 ,order_id:2 ,children: [
{menu_id: 5, parent_id:3 ,order_id:0 ,children:[
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]}
]},
{menu_id: 4, parent_id:0 ,order_id:3 ,children: [
{menu_id: 6, parent_id:4 ,order_id:0}
]},
{menu_id: 5, parent_id:3 ,order_id:0 ,children:[
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]},
{menu_id: 6, parent_id:4 ,order_id:0},
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]
menu_id == 5 返回之后,因为 5 的父节点不是 0 , 故 5 没了。
[
{menu_id: 1, parent_id:0 ,order_id:0},
{menu_id: 2, parent_id:0 ,order_id:1},
{menu_id: 3, parent_id:0 ,order_id:2 ,children: [
{menu_id: 5, parent_id:3 ,order_id:0 ,children:[
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]}
]},
{menu_id: 4, parent_id:0 ,order_id:3 ,children: [
{menu_id: 6, parent_id:4 ,order_id:0}
]},
{menu_id: 6, parent_id:4 ,order_id:0},
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]
最终达到的效果是:
[
{menu_id: 1, parent_id:0 ,order_id:0},
{menu_id: 2, parent_id:0 ,order_id:1},
{menu_id: 3, parent_id:0 ,order_id:2 ,children: [
{menu_id: 5, parent_id:3 ,order_id:0 ,children:[
{menu_id: 7, parent_id:5 ,order_id:0},
{menu_id: 8, parent_id:5 ,order_id:1}
]}
]},
{menu_id: 4, parent_id:0 ,order_id:3 ,children: [
{menu_id: 6, parent_id:4 ,order_id:0}
]}
]
记录一些思路:
按照上面设计表来说呢:
是不去存储父级元素名称的。遇到如下情况时(需要去展示父级元素名称),前端怎么办?
图 0
首先明确一点,在点出详情页的时候,是做了一次查询的。为什么呢?表格中的数据不一定够。而且有可能详情展示涉及其他表的更具体的信息,所以,详情查询一次是非常好的方案。
既然查询了。就可以要求后端给出 parentName 。
如果表格数据一定够的话,减少查询时非常好的选择。这个时候就需要保存一下我们调用 handleTree 之前的 数组。 根据 父节点id 利用 filter 过滤出 父节点名称。
总的思路是这样的:
// 在 created() 中,调用 getList() 在得到参数的时候,保存两个数组。 一个时表格绑定的数组(classifyList ),另外一个就是查询到的一维数组(querayData)。
/** 查询国家分类列表 */
getList() {
this.loading = true;
listClassify(this.queryParams).then(response => {
this.querayData = response.rows;
this.classifyList = this.handleTree(response.rows, "id", "parentId", "children", "0");
this.total = response.total;
this.loading = false;
});
},
但是此时出现一个问题。例如 图 2 .
我在点击搜素的时候调用的 也是 getList()
这个时候,queryData 变化了。不是全部数据了。只是一个子集。例如图 3 。 后面再使用这个数组去根据 Id 过滤名称就没有意义了。
此时在查询函数中为 queryData 的赋值做一个条件判断。
非全部查询,就不赋值给 queryData 。
/** 查询国家分类列表 */
getList() {
this.loading = true;
console.log(this.queryParams)
listClassify(this.queryParams).then(response => {
if (this.queryParams.name == undefined && this.queryParams.classifyLevel == undefined && this.queryParams.parentId == undefined && this.queryParams.sort == undefined) {
this.querayData = response.rows;
}
this.classifyList = this.handleTree(response.rows, "id", "parentId", "children", "0");
this.total = response.total;
this.loading = false;
});
},
当然,判断条件过多或者说不好判断的时候。也可以单独写一个全部查询,只在页面创建的时候调用一次。
图 1
图 2
图 3