• layui三级菜单渲染


    项目做完了,可以有时间写写博客了。 今天给大家讲解一下layui的三级动态加载菜单含后端代码。

    我是最近刚学的layui,非常感谢贤心大神。开发出这么牛逼ui的框架。
    声明:KingYiFan前段是渣渣,本次讲解用的前端js并非KingYiFan亲自封装只是稍作修改,非常感谢封装三级菜单CSDN的大神:yufengaotian	
    

    点我快速进入作者原文

    下图就是三级菜单效果。为什么要讲这个呢。

    file

    yufenggaotian大神也在博客中写道这个问题我就借用一下: file (图来着yufenggaotianCSDN博客)

    前端页面:

    //直接上代码吧
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
        <title>三级菜单展示</title>
    </head>
    <body>
    
    <div class="layui-side layui-bg-black" id="admin-side">
        <div class="layui-side-scroll">
            <ul class="layui-nav layui-nav-tree" id="nav" lay-filter="demo"></ul>
        </div>
    </div>
    </body>
    
    <link rel="stylesheet" href="/static/css/layui.css">
    <script src="/static/js/jquery.js" type="text/javascript" charset="utf-8"></script>
    <script src="/static/lib/layui/layui.js"></script>
    <script src="/static/js/api.js"></script>
    <script>
        //监听选中页签添加样式
        layui.config({
            base: '/static/lib/layui/'   //navbar组件js所在目录
        }).use('navbar', function() {
            var navbar = layui.navbar();
            navbar.set({
                elem: '#nav',
                url: "/menuInfo" //访问后台接口
            });
            navbar.render();
          
            //给选中的页签添加选中样式(解决刷新失效问题)
            var url = window.location.href.replace("//", "");
            var relUrl = url.substring(url.lastIndexOf("/") + 1);
            //去掉参数部分
            if (relUrl.indexOf("?") != -1) {
                relUrl = relUrl.split("?")[0];
            }
            $("#leftNavbar a").each(function () {
                var that = this;
                if ($(that).attr("href") == relUrl) {
                    $(that).parent().addClass("layui-this");
                    $(that).parents("li:eq(0)").addClass("layui-nav-itemed");
                    var nodes = $(that).parents("li:eq(0)").find("a .layui-nav-more");
                    if (nodes.length > 0) {
                        nodes.each(function () {
                            if ($(this).parents("dd:eq(0)").find("[href='" + relUrl +
                                "']").length > 0) {
                                $(this).parent().parent().addClass("layui-nav-itemed");
                            }
                        });
                    }
                }
            });
    
        });
    </script>
    </html>
    

    js部分可以不做修改

    layui.define(['element', 'common'], function (exports) {
        "use strict";
        var $ = layui.jquery,
            layer = parent.layer === undefined ? layui.layer : parent.layer,
            element = layui.element,
            common = layui.common,
            cacheName = 'tb_navbar';
    
        var Navbar = function () {
            /**
             *  默认配置
             */
            this.config = {
                elem: undefined, //容器
                data: undefined, //数据源
                url: undefined, //数据源地址
                type: 'GET', //读取方式
                cached: false, //是否使用缓存
                spreadOne: false //设置是否只展开一个二级菜单
            };
            this.v = '1.0.0';
        };
        //渲染
        Navbar.prototype.render = function () {
            var _that = this;
            var _config = _that.config;
            if (typeof (_config.elem) !== 'string' && typeof (_config.elem) !== 'object') {
                common.throwError('Navbar error: elem参数未定义或设置出错,具体设置格式请参考文档API.');
            }
            var $container;
            if (typeof (_config.elem) === 'string') {
                $container = $('' + _config.elem + '');
            }
            if (typeof (_config.elem) === 'object') {
                $container = _config.elem;
            }
            if ($container.length === 0) {
                common.throwError('Navbar error:找不到elem参数配置的容器,请检查.');
            }
            if (_config.data === undefined && _config.url === undefined) {
                common.throwError('Navbar error:请为Navbar配置数据源.')
            }
            if (_config.data !== undefined && typeof (_config.data) === 'object') {
                var html = getHtml(_config.data);
                $container.html(html);
                element.init();
                _that.config.elem = $container;
            } else {
                if (_config.cached) {
                    var cacheNavbar = layui.data(cacheName);
                    if (cacheNavbar.navbar === undefined) {
                        $.ajax({
                            type: _config.type,
                            url: _config.url,
                            async: false, //_config.async,
                            dataType: 'json',
                            success: function (result, status, xhr) {
                                //添加缓存
                                layui.data(cacheName, {
                                    key: 'navbar',
                                    value: result
                                });
                                var html = getHtml(result);
                                $container.html(html);
                                element.init();
                            },
                            error: function (xhr, status, error) {
                                common.msgError('Navbar error:' + error);
                            },
                            complete: function (xhr, status) {
                                _that.config.elem = $container;
                            }
                        });
                    } else {
                        var html = getHtml(cacheNavbar.navbar);
                        $container.html(html);
                        element.init();
                        _that.config.elem = $container;
                    }
                } else {
                    //清空缓存
                    layui.data(cacheName, null);
                    $.ajax({
                        type: _config.type,
                        url: _config.url,
                        async: false, //_config.async,
                        dataType: 'json',
                        success: function (result, status, xhr) {
                            var html = getHtml(result);
                            $container.html(html);
                            element.init();
                        },
                        error: function (xhr, status, error) {
                            common.msgError('Navbar error:' + error);
                        },
                        complete: function (xhr, status) {
                            _that.config.elem = $container;
                        }
                    });
                }
            }
    
            //只展开一个二级菜单
            if (_config.spreadOne) {
                var $ul = $container.children('ul');
                $ul.find('li.layui-nav-item').each(function () {
                    $(this).on('click', function () {
                        $(this).siblings().removeClass('layui-nav-itemed');
                    });
                });
            }
            return _that;
        };
        /**
         * 配置Navbar
         * @param {Object} options
         */
        Navbar.prototype.set = function (options) {
            var that = this;
            that.config.data = undefined;
            $.extend(true, that.config, options);
            return that;
        };
        /**
         * 绑定事件
         * @param {String} events
         * @param {Function} callback
         */
        Navbar.prototype.on = function (events, callback) {
            var that = this;
            var _con = that.config.elem;
            if (typeof (events) !== 'string') {
                common.throwError('Navbar error:事件名配置出错,请参考API文档.');
            }
            var lIndex = events.indexOf('(');
            var eventName = events.substr(0, lIndex);
            var filter = events.substring(lIndex + 1, events.indexOf(')'));
            if (eventName === 'click') {
                if (_con.attr('lay-filter') !== undefined) {
                    _con.children('ul').find('li').each(function () {
                        var $this = $(this);
                        if ($this.find('dl').length > 0) {
                            var $dd = $this.find('dd').each(function () {
                                $(this).on('click', function () {
                                    var $a = $(this).children('a');
                                    var href = $a.data('url');
                                    var icon = $a.children('i:first').data('icon');
                                    var title = $a.children('cite').text();
                                    var data = {
                                        elem: $a,
                                        field: {
                                            href: href,
                                            icon: icon,
                                            title: title
                                        }
                                    }
                                    callback(data);
                                });
                            });
                        } else {
                            $this.on('click', function () {
                                var $a = $this.children('a');
                                var href = $a.data('url');
                                var icon = $a.children('i:first').data('icon');
                                var title = $a.children('cite').text();
                                var data = {
                                    elem: $a,
                                    field: {
                                        href: href,
                                        icon: icon,
                                        title: title
                                    }
                                }
                                callback(data);
                            });
                        }
                    });
                }
            }
        };
        /**
         * 清除缓存
         */
        Navbar.prototype.cleanCached = function () {
            layui.data(cacheName, null);
        };
        /**
         * 获取html字符串
         * @param {Object} data
         */
        function getHtml(data) {
            var ulHtml = '<ul class="layui-nav layui-nav-tree beg-navbar">';
            for (var i = 0; i < data.length; i++) {
                if (data[i].spread) {
                    ulHtml += '<li class="layui-nav-item layui-nav-itemed">';
                } else {
                    ulHtml += '<li class="layui-nav-item">';
                }
    
                if (data[i].children !== undefined && data[i].children !== null && data[i].children.length > 0) {
    
                    ulHtml += '<a href="javascript:;">' + data[i].title;
                    ulHtml += '<span class="layui-nav-more"></span>';
                    ulHtml += '</a>';
                    ulHtml += '<dl class="layui-nav-child">';
                    //二级菜单
                    for (var j = 0; j < data[i].children.length; j++) {
                        //是否有孙子节点
                        if (data[i].children[j].children !== undefined && data[i].children[j].children !== null && data[i].children[j].children.length > 0) {
                            ulHtml += '<dd>';
                            ulHtml += '<a href="javascript:;">' + data[i].children[j].title;
                            ulHtml += '<span class="layui-nav-more"></span>';
                            ulHtml += '</a>';
                            //三级菜单
                            ulHtml += '<dl class="layui-nav-child">';
                            var grandsonNodes = data[i].children[j].children;
                            for (var k = 0; k < grandsonNodes.length; k++) {
                                ulHtml += '<dd>';
                                ulHtml += '<a target="xq" href="'+ grandsonNodes[k].href +'">' + grandsonNodes[k].title + '</a>';
                                ulHtml += '</dd>';
                            }
                            ulHtml += '</dl>';
                            ulHtml += '</dd>';
                        }else{
                            ulHtml += '<dd>';
                            ulHtml += '<a target="xq" href="'+data[i].children[j].href+'">' + data[i].children[j].title;
                            ulHtml += '</a>';
                            ulHtml += '</dd>';
                        }
                        //ulHtml += '<dd title="' + data[i].children[j].title + '">';
                    }
                    ulHtml += '</dl>';
                } else {
                    var dataUrl = (data[i].href !== undefined && data[i].href !== '') ? 'data-url="' + data[i].href + '"' : '';
                    //ulHtml += '<a href="javascript:;" ' + dataUrl + '>';
                    ulHtml += '<a href="' + data[i].href + '"' + dataUrl + 'target="xq">';
                    if (data[i].icon !== undefined && data[i].icon !== '') {
                            ulHtml +=  '<i  class="layui-icon" >' +'<img src=' +data[i].icon +'>'+'</i>';
                    }
                    ulHtml += '<cite>' + data[i].title + '</cite>';
                    ulHtml += '</a>';
                }
                ulHtml += '</li>';
            }
            ulHtml += '</ul>';
    
            return ulHtml;
        }
    
        var navbar = new Navbar();
    
        exports('navbar', function (options) {
            return navbar.set(options);
        });
    });
    common.js
    layui.define(['layer'], function(exports) {
        "use strict";
    
        var $ = layui.jquery,
            layer = layui.layer;
    
        var common = {
            /**
             * 抛出一个异常错误信息
             * @param {String} msg
             */
            throwError: function(msg) {
                throw new Error(msg);
                return;
            },
            /**
             * 弹出一个错误提示
             * @param {String} msg
             */
            msgError: function(msg) {
                layer.msg(msg, {
                    icon: 5
                });
                return;
            }
        };
    
        exports('common', common);
    });
    
    
    json格式:
    [
    	{
    		"title": "我是一级",
    		"icon": "",
    		"spread": true,
    		"href": "",
    		"children": [
    			{
    				"title": "我是二级",
    				"icon": "",
    				"href": "",
    				"spread": true,
    				"children": [
    					{
    						"title": "我是三级",
    						"icon": " ",
    						"href": "https://cnbuilder.cn/"
    					},
    					{
    						"title": "我也是三级",
    						"icon": " ",
    						"href": "https://cnbuilder.cn/"
    					}
    				]
    			}
    		]
    	}
    ]
    
    

    java代码部分 1、用到了MyBatisPlus技术 2、用到了Lombok 所以代码量很少

    controller:
    	/**
         * 1、根据用户id查询角色
         * 2、遍历角色查询资源
         * KingYiFan create By 2019/03/14
         * @return
         */
        @GetMapping("/menuInfo")
        @ResponseBody
        public Object menuInfo() {
            if (getShiroUser().getId() == null) {
                return "redirect:/login";
            }
    		//查询用户的菜单
            List<BsResource> bsResources = bsRoleService.selectMenuByUserId(getShiroUser().getId());
            //根据菜单封装需要的格式
    		List<BsResource> trees = TreeBuilder.bulid(bsResources);
            return trees;
        }
    
    service接口
     @Override
        public List<BsResource> selectMenuByUserId(Long userId) {
    
            //根据用户id查询所有角色
            List<Long> roleIdList = bsTenantRoleMapper.selectRoleIdListByTenantId(userId);
            Set<String> urlSet = new HashSet<String>();
            //遍历全部角色
            for (Long roleId : roleIdList) {
                //根据角色获取当前资源
                List<Map<String, String>> resourceList = bsRoleMapper.selectResourceListByRoleId(roleId);
                for (Map<String, String> map : resourceList) {
                    urlSet.add(map.get("id"));
                }
            }
            //根据id查询菜单
            List<BsResource> bsResources = bsResourceMapper.selectBatchIds(urlSet);
            return bsResources;
        }
    

    实体类

    package cn.cnbuilder.entity;
    
    import com.baomidou.mybatisplus.annotations.TableField;
    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.hcr.model.BaseEntity;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    import lombok.experimental.Accessors;
    
    import java.util.List;
    
    /**
     * <p>
     * 资源表 这个是全局的资源表
     * </p>
     *
     * @author KingYiFan
     * @since 2019-03-14
     */
    @Data
    @EqualsAndHashCode(callSuper = true)
    @Accessors(chain = true)
    public class BsResource {
    
        private static final long serialVersionUID = 1L;
    
        private Long id;
    
        @TableField(exist = false)
        private List<BsResource> children;
        /**
         * 资源名称
         */
        private String title;
    
        /**
         * 资源路径
         */
        private String href;
    
        /**
         * 资源介绍
         */
        private String description;
    
        /**
         * 资源图标
         */
        private String icon;
    
        /**
         * 父级资源id
         */
        @TableField(value = "p_id")
        private Integer pId;
    
        /**
         * 排序
         */
        private String seq;
    
        /**
         * 状态
         */
        private Integer status;
    
        /**
         * 打开状态
         */
        private Integer spread;
    
        /**
         * 资源类别
         */
        private Integer resourceType;
    }
    
    

    工具类

    package cn.cnbuilder.utils;
    
    import cn.cnbuilder.entity.BsResource;
    
    import java.util.List;
    
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by KingYiFan on  2019/03/14.
     */
    public class TreeBuilder {
    
        /**
         * 两层循环实现建树
         *
         * @param BsResources 传入的树节点列表
         * @return
         */
        public static List<BsResource> bulid(List<BsResource> BsResources) {
    
            List<BsResource> trees = new ArrayList<BsResource>();
    
            for (BsResource BsResource : BsResources) {
    
                if (BsResource.getPId()==0) {
                    trees.add(BsResource);
                }
    
                for (BsResource it : BsResources) {
                    if (it.getPId() == BsResource.getId().intValue()) {
                        if (BsResource.getChildren() == null) {
                            BsResource.setChildren(new ArrayList<BsResource>());
                        }
                        BsResource.getChildren().add(it);
                    }
                }
            }
            return trees;
        }
    
        /**
         * 使用递归方法建树
         *
         * @param BsResources
         * @return
         */
        public static List<BsResource> buildByRecursive(List<BsResource> BsResources) {
            List<BsResource> trees = new ArrayList<BsResource>();
            for (BsResource BsResource : BsResources) {
                if ("0".equals(BsResource.getPId())) {
                    trees.add(findChildren(BsResource, BsResources));
                }
            }
            return trees;
        }
    
        /**
         * 递归查找子节点
         *
         * @param BsResources
         * @return
         */
        public static BsResource findChildren(BsResource BsResource, List<BsResource> BsResources) {
            for (BsResource it : BsResources) {
                if (BsResource.getId().equals(it.getPId())) {
                    if (BsResource.getChildren() == null) {
                        BsResource.setChildren(new ArrayList<BsResource>());
                    }
                    BsResource.getChildren().add(findChildren(it, BsResources));
                }
            }
            return BsResource;
        }
    
    
        public static void main(String[] args) {
            List<BsResource> list = new ArrayList<BsResource>();
            List<BsResource> trees = TreeBuilder.bulid(list);
            List<BsResource> trees_ = TreeBuilder.buildByRecursive(list);
    
        }
    }
    

    这就是layui动态三级菜单渲染。有什么不懂的可以跟我联系。


    鼓励作者写出更好的技术文档,就请我喝一瓶哇哈哈哈哈哈哈哈。。

    微信:

    支付宝:


    感谢一路支持我的人。。。。。
    
    Love me and hold me
    QQ:69673804(16年老号)
    EMAIL:69673804@qq.com
    友链交换
    如果有兴趣和本博客交换友链的话,请按照下面的格式在评论区进行评论,我会尽快添加上你的链接。
    

    网站名称:KingYiFan’S Blog
    网站地址:http://blog.cnbuilder.cn
    网站描述:年少是你未醒的梦话,风华是燃烬的彼岸花。
    网站Logo/头像: [头像地址](https://blog.cnbuilder.cn/upload/2018/7/avatar20180720144536200.jpg)
    
  • 相关阅读:
    粘包_Server
    初见UDP_Server
    初见UDP_Client
    TCP/UDP协议
    网络编程相关概念
    mmap实现大文件快速拷贝
    生成这消费者问题(多线程实现)
    线程同步互斥实现资源访问
    信号灯(线程互斥)
    线程属性
  • 原文地址:https://www.cnblogs.com/kingyifan/p/11721447.html
Copyright © 2020-2023  润新知