json菜单的遍历渲染

415 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

在我工作中遇到的项目里,菜单通常是一个json格式的文件。
在这个json中有菜单的id、菜单名称、图标class、排序号、权限清单id、嵌套子菜单等信息。
其实细看起来,包含的信息还是很多的。
就因为这个信息过多,很多时候如何把他渲染到页面上,会很棘手。
不要怕,直接不看干扰信息,找到关键信息,一个遍历,不行就再来一个遍历。

无论用多low的方法,哪怕if-else嵌套也行啊,第一步的任务就是:先用代码实现它。
然后再逐步优化它

菜单的json格式

要说这个json格式,通常有两种:一维、多维(嵌套)

//一维
[
    {},
    {},
    {},
    {}
    ....
]

//多维
[{},
    [
        {},
            [
                {},
                {}
            ]
    ],
    [
        {},
        {}
    ]
]

这两种遍历的方式不一样,但是也差不多
因为既然是菜单,肯定不只有一级菜单,一般是多级(遍历程序默认支持无穷级那种)
一维格式同样可以达到多级菜单的目的,加个字段即可...

遍历一维菜单的json文件

废话不多说,直接上菜单json

var data = [
    {
        "id": 1,
        "name": "办公管理",
        "pid": 0
        },
    {
        "id": 2,
        "name": "请假申请",
        "pid": 1
    },
    {
        "id": 3,
        "name": "出差申请",
        "pid": 1
    },
    {
        "id": 4,
        "name": "请假记录",
        "pid": 2
    },
    {
        "id": 5,
        "name": "系统设置",
        "pid": 0
    },
    {
        "id": 6,
        "name": "权限管理",
        "pid": 5
    },
    {
        "id": 7,
        "name": "用户角色",
        "pid": 6
    },
    {
        "id": 8,
        "name": "菜单设置",
        "pid": 6
    }
]

如上 pid 表示 菜单的父级id,从而实现层级效果!如果pid为空或0,则表示一级根菜单。
想想看如何遍历比较好?

思路分析: 循环遍历这个json文件
然后根据当前id,找到所有pid和这个id相同的项,组成一个临时数组 ---> 这个就是当前的子菜单集合 如果临时数组中id,还有pid和它相同,那就是子菜单的子菜单....这不就是递归了

关键:对,把如何找子菜单集合的方法单独拿出来,因为它和递归业务没有直接关系,这种找集合的逻辑不要放到循环遍历的逻辑里面

我的代码如下

<script>
    let menu = "";
    let app = {
        getTree: function(id, arr) {
            let childArr = this.getParentArray(id, arr);
                if (childArr.length > 0) {
                    menu += "<ul>";
                    for (let i in childArr) {
                        menu += "<li>" + childArr[i].name;
                        this.getTree(childArr[i].id, arr); //递归调用
                        menu += "</li>";
                    }
                menu += "</ul>";
            }
        },
        
        //子菜单集合获取方法
        getParentArray: function(id, arr) {
            let newArr = [];
                for (let i in arr) {
                    if (arr[i].pid === id) {
                        newArr.push(arr[i]);
                    }
                }
            return newArr;
        }
    };

//调用并输出
app.getTree(0, data);
$(document.body).append(menu);

渲染效果 image.png

看完代码是不是很简单?
但真要空手去实现,一次性并不会写的那么完美,而是多次修改迭代,抽离之后得出来的代码,虽说不算什么高深,但还是需要一定技巧的
另外还需要说一点的是:找集合的方法,其实就是在杂乱无序的对象中找到属于自己的下级,至于下级的下级,或上级,那就不是本次遍历考虑的了,而是递归方法里考虑了,它就像一个螺旋结构一样。
再重复一遍,而找子集的方法抽出来很重要,不然方法会显得臃肿(在这里的demo不明显,但是实际项目中会复杂的多)

另外,如何遍历多维菜单json文件,下文再说吧,本文先到这里。
留个坑,大家可以先想想代码怎么写

文末总结

有时候遇到一个棘手的问题时,首先不能怕
找到切入点,迎难而上,很快就能发现,问题并不难解决
先写出雏形,慢慢再优化,最后找到完美代码
万变不离其宗,难的是开头,要不怎么说:万事开头难呢