HTML + CSS + JS实现页面树形菜单展示功能

功能介绍

  1. 后台管理端的角色管理功能;
  2. 树型菜单能够正确展示,包括父节点选中子节点全选,子节点全部取消父节点也取消,选中任一子项其父级自动选中,以及其他正常操作的展示;
  3. 由于是html+css+js编写,通过checked属性的确可以正确更改样式,但实际使用会发现页面无法实时渲染,从而导致父级全选子级不会全选等问题,可以自己更改代码验证。如果办法消除此问题,欢迎回复我;
  4. 通过name属性标记哪些节点是选中的,在添加角色时,遍历获取所有"name"="1"的input的value(角色id),提交到后端,从而实现功能。

后端代码

通过递归查出树形菜单结构

private List<WzAuthorityBO> getAuthorityTree(String parentId) {
    List<WzAuthorityBO> list = new ArrayList<>();
    List<WzAuthority> wzAuthorities = wzAuthorityMapper.selectWzAuthorityList(parentId);
    if (!CollectionUtils.isEmpty(wzAuthorities)) {
        for (WzAuthority item : wzAuthorities) {
            WzAuthorityBO wzAuthorityBO = new WzAuthorityBO();
            BeanUtils.copyProperties(item, wzAuthorityBO);
            wzAuthorityBO.setChildren(this.getAuthorityTree(item.getId()));
            list.add(wzAuthorityBO);
        }
    }
    return list;
}

返回结构如下:

{
    "code": "000000",
    "msg": "操作成功",
    "data": {
        "menus": [
            {
                "id": "2",
                "authorityName": "账号中心",
                "type": 0,
                "path": null,
                "level": null,
                "parentId": "0",
                "isRequireAuth": null,
                "createTime": null,
                "updateTime": null,
                "children": [
                    {
                        "id": "32",
                        "authorityName": "账号列表",
                        "type": 0,
                        "path": null,
                        "level": null,
                        "parentId": "2",
                        "isRequireAuth": null,
                        "createTime": null,
                        "updateTime": null,
                        "children": [
                            {
                                "id": "33",
                                "authorityName": "列表接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "32",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            }
                        ]
                    },
                    {
                        "id": "91",
                        "authorityName": "角色列表",
                        "type": 0,
                        "path": null,
                        "level": null,
                        "parentId": "2",
                        "isRequireAuth": null,
                        "createTime": null,
                        "updateTime": null,
                        "children": []
                    }
                ]
            },
            {
                "id": "89",
                "authorityName": "企业中心",
                "type": 0,
                "path": null,
                "level": null,
                "parentId": "0",
                "isRequireAuth": null,
                "createTime": null,
                "updateTime": null,
                "children": [
                    {
                        "id": "86",
                        "authorityName": "变更管理",
                        "type": 0,
                        "path": null,
                        "level": null,
                        "parentId": "89",
                        "isRequireAuth": null,
                        "createTime": null,
                        "updateTime": null,
                        "children": [
                            {
                                "id": "49",
                                "authorityName": "列表接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "86",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            }
                        ]
                    },
                    {
                        "id": "87",
                        "authorityName": "机构列表",
                        "type": 0,
                        "path": null,
                        "level": null,
                        "parentId": "89",
                        "isRequireAuth": null,
                        "createTime": null,
                        "updateTime": null,
                        "children": [
                            {
                                "id": "29",
                                "authorityName": "列表导出",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "87",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "58",
                                "authorityName": "详情接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "87",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "59",
                                "authorityName": "审核接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "87",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "60",
                                "authorityName": "查询接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "87",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "61",
                                "authorityName": "列表路由",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "87",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "65",
                                "authorityName": "审核路由",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "87",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "77",
                                "authorityName": "详情路由",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "87",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            }
                        ]
                    },
                    {
                        "id": "88",
                        "authorityName": "企业列表",
                        "type": 0,
                        "path": null,
                        "level": null,
                        "parentId": "89",
                        "isRequireAuth": null,
                        "createTime": null,
                        "updateTime": null,
                        "children": [
                            {
                                "id": "68",
                                "authorityName": "标签接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "88",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "69",
                                "authorityName": "列表接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "88",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "70",
                                "authorityName": "信息接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "88",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "71",
                                "authorityName": "详情路由",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "88",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "82",
                                "authorityName": "操作接口",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "88",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            },
                            {
                                "id": "90",
                                "authorityName": "列表导出",
                                "type": 0,
                                "path": null,
                                "level": null,
                                "parentId": "88",
                                "isRequireAuth": null,
                                "createTime": null,
                                "updateTime": null,
                                "children": []
                            }
                        ]
                    }
                ]
            }
        ],
        "checkedKeys": []
    }
}

前端代码

CSS样式

/**
 * DOM树
 */
ul>li{
    list-style: none;
}
/* 可展开*/
.switch-open {
    margin-left:-12px;
    border:6px solid transparent;
    display:inline-block;
    width:0px;
    height:0px;
    border-top-color: black;
    margin-right: 5px;
}
/* 展开完毕*/
.switch-close {
    margin-left:-12px;
    border:6px solid transparent;
    display:inline-block;
    width:0px;
    height:0px;
    border-left-color: black;
    margin-bottom: 2px;
    margin-right: 5px;
}

/* 改变CheckBox样式*/
input[type='checkbox']{
    width: 20px;
    height: 20px;
    -webkit-appearance:none;
    -moz-appearance: none;
    border: 1px solid #c9c9c9;
    border-radius: 3px;
    outline: none;
    color:white;
    text-align: center;
    margin-right: 5px;
}

input[type='checkbox']:before {
    content: '√ ';
    color:transparent;
}

input[type=checkbox]:checked{
    background-color: #409eff;
}

input[type=checkbox]:checked:before{
    content: '√';
    color:white;
    font-weight: bold;
}

JS

function getRoleMenuTree(roleId) {
    var param = {};
    param.roleId = roleId;
    $.ajax({
        type: 'get',
        url: ctx+'/user/admin/perm/roleMenuTreeselect',
        cache: false,  //禁用缓存
        data: param,
        dataType: 'json',
        success: function(res) {
            if (res.code === '000000') {
                var menus = res.data.menus;
                generate(menus, document.getElementById('container'));
            }
        },
        error() {
            console.log('error');
        }
    })
}

//这里生成DOM
function generate(menus, par) {
    for (var i = 0; i < menus.length; i++) {
        var wzAuthority = menus[i];
        var ele = document.createElement('li');
        if(wzAuthority.children !== null && wzAuthority.children.length == 0) {
            if (wzAuthority.checked) {
                ele.innerHTML=' <input type="checkbox" οnclick="checkSingleChange(this)" checked="true" name="1" value="' + wzAuthority.id + '"></input>'+wzAuthority.authorityName;
            } else {
                ele.innerHTML=' <input type="checkbox" οnclick="checkSingleChange(this)"  value="' + wzAuthority.id + '"></input>'+wzAuthority.authorityName;
            }
        } else {
            if (wzAuthority.checked) {
                ele.innerHTML='<span><span class="switch-open" οnclick="toggle(this)"></span><input type="checkbox" checked="true" name="1" οnclick="checkChange(this)" value="' + wzAuthority.id + '"></input>' + wzAuthority.authorityName + '</span>';
            } else {
                ele.innerHTML='<span><span class="switch-open" οnclick="toggle(this)"></span><input type="checkbox" οnclick="checkChange(this)" value="' + wzAuthority.id + '"></input>' + wzAuthority.authorityName + '</span>';
            }
            var nextpar = document.createElement('ul');
            ele.appendChild(nextpar);
            generate(wzAuthority.children, nextpar);
        }
        par.appendChild(ele);
    }
}

//处理展开和收起
function toggle(eve) {
    var par=eve.parentNode.nextElementSibling;
    if(par.style.display=='none') {
        par.style.display='block';
        eve.className='switch-open';
    } else {
        par.style.display='none';
        eve.className='switch-close';
    }
}

//处理全部勾选和全部不选
function checkChange(eve) {
    var oul = eve.parentNode.nextElementSibling;
    if($(eve).prop("checked")){
        $(eve).parent().next().find("input[type='checkbox']").prop("checked",true);
        // 下面是为了提交的时候,我能知道哪个权限是被选中的,
        // 但是使用.setAttribute("checked", true)会导致页面勾选的显示异常,因此多加一个name属性标记,同时对页面显示无影响
        eve.parentNode.parentNode.firstChild.querySelectorAll('input')[0].setAttribute("name", "1");
        for(var i=0;i<oul.querySelectorAll('input').length;i++) {
            if ("1" !== oul.querySelectorAll('input')[i].getAttribute("name")) {
                oul.querySelectorAll('input')[i].setAttribute("name", "1");
            }
        }
    }else{
        $(eve).parent().next().find("input[type='checkbox']").filter(":checked").prop("checked",false).removeAttr("name");
        eve.parentNode.parentNode.firstChild.querySelectorAll('input')[0].removeAttribute("name");
        for(var i=0;i<oul.querySelectorAll('input').length;i++) {
            oul.querySelectorAll('input')[i].removeAttribute("name");
        }
    }
}

// 处理单个勾选和单个不选
function checkSingleChange(eve) {
    var oul = eve.parentNode.nextElementSibling;
    if($(eve).prop("checked")){
        $(eve).parent().parent().prev().find("input[type='checkbox']").prop("checked",true);
        // 子项选中之后,子父级都要有name标记
        // 父级加标记
        eve.parentNode.parentNode.previousSibling.childNodes.item(1).setAttribute("name", "1");
        // 自己加标记
        eve.setAttribute("name", "1");
    }else{
        // 如果取消选中,子级不存在勾选中的,父级删除标记
        if ($(eve).parent().siblings().find("input[type='checkbox']").filter(":checked").length === 0) {
            $(eve).parent().parent().prev().find("input[type='checkbox']").filter(":checked").prop("checked",false);
            eve.parentNode.parentNode.previousSibling.childNodes.item(1).removeAttribute("name");
        }
        //删除自己的标记
        eve.removeAttribute("name");
    }
}

【JS旧代码,有问题】

  1. 原来的思路是通过设置checked属性,控制选中与否的显示,最后发现树型菜单多点击几次就会出现异常展示,比如明明没有checked仍然显示、有checked却不显示。是由于原生js无法动态渲染页面(可能是我比较菜,有知道解决方案的大佬欢迎回复解决我的问题,谢谢。)
  2. 之后就想到,我用checked主要是为了找到我到底选中了哪些角色,后来就想到换个name属性标记,从而解决该问题。JS代码在上面。
//这里生成DOM
function generate(menus, par) {
    for (var i = 0; i < menus.length; i++) {
        var wzAuthority = menus[i];
        var ele = document.createElement('li');
        if(wzAuthority.children !== null && wzAuthority.children.length == 0) {
            if (wzAuthority.checked) {
                ele.innerHTML=' <input type="checkbox" οnclick="checkSingleChange(this)" checked="true" value="' + wzAuthority.id + '"></input>'+wzAuthority.authorityName;
            } else {
                ele.innerHTML=' <input type="checkbox" οnclick="checkSingleChange(this)"  value="' + wzAuthority.id + '"></input>'+wzAuthority.authorityName;
            }
            // ele.innerHTML=' <input type="checkbox" οnclick="checkSingleChange(this)"  value="' + wzAuthority.id + '"></input>'+wzAuthority.authorityName;
        } else {
            if (wzAuthority.checked) {
                ele.innerHTML='<span><span class="switch-open" οnclick="toggle(this)"></span><input type="checkbox" checked="true" οnclick="checkChange(this)" value="' + wzAuthority.id + '"></input>' + wzAuthority.authorityName + '</span>';
            } else {
                ele.innerHTML='<span><span class="switch-open" οnclick="toggle(this)"></span><input type="checkbox" οnclick="checkChange(this)" value="' + wzAuthority.id + '"></input>' + wzAuthority.authorityName + '</span>';
            }
            // ele.innerHTML='<span><span class="switch-open" οnclick="toggle(this)"></span><input type="checkbox" οnclick="checkChange(this)" value="' + wzAuthority.id + '"></input>' + wzAuthority.authorityName + '</span>';
            var nextpar = document.createElement('ul');
            ele.appendChild(nextpar);
            generate(wzAuthority.children, nextpar);
        }
        par.appendChild(ele);
    }
}

//处理展开和收起
function toggle(eve) {
    var par=eve.parentNode.nextElementSibling;
    if(par.style.display=='none') {
        par.style.display='block';
        eve.className='switch-open';
    } else {
        par.style.display='none';
        eve.className='switch-close';
    }
}

//处理全部勾选和全部不选
function checkChange(eve) {
    var oul = eve.parentNode.nextElementSibling;
    var parent = oul.parentNode.firstChild.childNodes.item(1);
    if(eve.checked) {
        parent.setAttribute("checked", "true");
        for(var i=0;i<oul.querySelectorAll('input').length;i++) {
            if ("true" != oul.querySelectorAll('input')[i].getAttribute("checked")) {
                oul.querySelectorAll('input')[i].setAttribute("checked", "true");
            }
        }
    } else {
        parent.setAttribute("checked","false");
        console.log('当前元素---',oul)
        for(var i=0;i<oul.querySelectorAll('input').length;i++) {
            oul.querySelectorAll('input')[i].removeAttribute("checked");
        }
    }

}

//处理单个勾选和单个不选
function checkSingleChange(eve) {
    console.log(eve)
    if(eve.checked) {
        eve.setAttribute("checked", "true");
        //子元素选中,则父元素选中
        console.log(eve.parentNode.parentNode.previousSibling.childNodes.item(1))
        eve.parentNode.parentNode.previousSibling.childNodes.item(1).setAttribute("checked", "true");
    } else {
        eve.removeAttribute("checked");
        //如果子元素全部清除,父元素也取消选中
        for(var i=0;i<eve.parentNode.parentNode.querySelectorAll('input').length;i++) {
            let inputElement = eve.parentNode.parentNode.querySelectorAll('input')[i];
            if (inputElement.getAttribute("checked") == "true") {
                return;
            }
        }
        eve.parentNode.parentNode.previousSibling.childNodes.item(1).removeAttribute("checked");
    }
}

HTML

<div class="warp">
	<ul id="container">
	</ul>
</div>

效果展示

在这里插入图片描述

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Bootstrap中实现树形菜单实现联动数据,可以使用Bootstrap Treeview插件。以下是实现步骤: 1.在页面中引入jQuery和Bootstrap Treeview插件的CSSJS文件。 ```html <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-treeview/1.2.0/bootstrap-treeview.min.css" /> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-treeview/1.2.0/bootstrap-treeview.min.js"></script> ``` 2.在页面中添加两个用于显示树形结构的容器元素。 ```html <div id="treeview1"></div> <div id="treeview2"></div> ``` 3.使用jQuery将数据渲染到树形结构中,并实现联动数据。 ```javascript $(function() { var data1 = [ { text: "节点1", value: "1", nodes: [ { text: "子节点1", value: "11" }, { text: "子节点2", value: "12" } ] }, { text: "节点2", value: "2", nodes: [ { text: "子节点3", value: "21" }, { text: "子节点4", value: "22" } ] } ]; var data2 = [ { text: "请选择", value: "" } ]; $('#treeview1').treeview({ data: data1, onNodeSelected: function(event, node) { var selectedValue = node.value; data2 = [ { text: "请选择", value: "" } ]; if(selectedValue == "1") { data2.push({ text: "子节点1", value: "11" }); data2.push({ text: "子节点2", value: "12" }); } else if(selectedValue == "2") { data2.push({ text: "子节点3", value: "21" }); data2.push({ text: "子节点4", value: "22" }); } $('#treeview2').treeview({ data: data2 }); } }); $('#treeview2').treeview({ data: data2 }); }); ``` 以上代码将生成两个树形结构,第一个结构为根节点为"节点1"和"节点2"的树形菜单,第二个结构为初始只有一个"请选择"节点的树形菜单。当在第一个结构中选择一个节点时,第二个结构会根据所选节点的值动态生成子节点。可以根据实际需要修改数据和样式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值