layui动态渲染生成左侧3级菜单(根据后台返回数据)

2023-05-16

声明:这里非常感谢闲心大神,开源了非常好用的前端UI框架,layui,如有侵权请联系我。当然闲心在2.0版本的layuiAdmin已经支持了,不过是收费版的,需要的同学可以自行购买,网址:http://www.layui.com/admin/pro/

本人在做管理后台事用到了左侧的导航列表,但是管理后台进来的菜单是根据不同账户的权限,显示不同的菜单。这时候需要动态的渲染左侧的列表。但是1.0版本只是更新到2级菜单,不满足如下图的3级菜单需求,只能自己动手,改造源码

话不多说,上代码:

1.html部分,我需要一个容器用于渲染菜单

<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>

接下来是插件以及相关JS,css引入 ,注意:路径问题,换成自己本地的路径

<link rel="stylesheet" href="../layui/css/layui.css">
<script src="../lib/jquery-1.12.2.js" type="text/javascript" charset="utf-8"></script>
<script src="../layui/layui.js"></script>

2.js部分

<script>
	//监听选中页签添加样式
    layui.config({
        base: '../layui/'   //navbar组件js所在目录
    }).use('navbar', function() {
        var navbar = layui.navbar();
        navbar.set({
            elem: '#nav',
            url: "../layui/nav2.json"   //数据源地址,我用了本地写的json数据
        });
        navbar.render();
        //下面的部分不是必须的
        navbar.on('click(demo)', function(data) {
            console.log(data.elem);
            console.log(data.field.title);//标题
            console.log(data.field.icon);//图标
            console.log(data.field.href);//调转地址
            layer.msg(data.field.href);
        });
        
       //给选中的页签添加选中样式(解决刷新失效问题)
       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>

重点来了:navbar,js

/**
 * navbar.js
 * @author 御风 <1945199284@qq.com>
 */
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 href="'+ grandsonNodes[k].href +'">' + grandsonNodes[k].title + '</a>';
	                            ulHtml += '</dd>';
	                        }
	                    ulHtml += '</dl>';
	                    ulHtml += '</dd>';
                    }else{
                    	ulHtml += '<dd>';
                        ulHtml += '<a 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 + '>';
                if (data[i].icon !== undefined && data[i].icon !== '') {
                    if (data[i].icon.indexOf('fa-') !== -1) {
                        ulHtml += '<i class="fa ' + data[i].icon + '" aria-hidden="true" data-icon="' + data[i].icon + '"></i>';
                    } else {
                        ulHtml += '<i class="layui-icon" data-icon="' + data[i].icon + '">' + 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

/**
 * common.js
 * @author 御风 <1945199284@qq.com>
 */
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);
});

3.返回数据json格式

[
  {
    "title": "首页",
    "icon": " ",
    "spread": true,
    "href": ""
  },
  {
    "title": "一级导航",
    "icon": "fa-stop-circle",
    "spread": true,
    "href": "http://www.baidu.com",
    "children": [
      {
        "title": "二级导航",
        "icon": "",
        "href": "lala.html",
        "spread": true,
        "children": [
          {
            "title": "三级导航",
            "icon": " ",
            "href": "button.html"
          },
          {
            "title": "三级导航",
            "icon": " ",
            "href": "buttwswon.html"
          }
        ]
      }
    ]
  },
  {
    "title": "一级导航",
    "icon": "fa-stop-circle",
    "spread": true,
    "href": "http://www.baidu.com"

  },
  {
    "title": "一级导航",
    "icon": "fa-stop-circle",
    "spread": true,
    "href": "http://www.baidu.com"

  },
  {
    "title": "一级导航",
    "icon": "fa-stop-circle",
    "spread": true,
    "href": "http://www.baidu.com"

  }
]

总结:渲染dom,只要的思路就是用了2次for循环,遍历后台返回的数据。觉得有用的话,点歌赞再走吧!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

layui动态渲染生成左侧3级菜单(根据后台返回数据) 的相关文章

随机推荐

  • Gazebo配置与控制不同的无人机 仿真

    PX4 Firmware 配置与控制不同的无人机 配置方法控制方法 XTDrone目前支持多旋翼飞行器 xff08 multirotor xff09 固定翼飞行器 xff08 plane xff09 可垂直起降固定翼飞行器 xff08 vt
  • 基于采样的路径规划算法RRT的优化:RRT*,Kinodynamic-RRT*,Anytime-RRT *,Informed RRT *

    基于采样的路径规划算法RRT的优化 RRT 算法Kinodynamic RRT Anytime RRT Informed RRT 关于搜索树按搜索方向生长的计算方法 基本的基于采样的路径规划算法RRT xff0c 在地图中进行采样取点 xf
  • 碰到的bug,解决方法

    问题解决 1 build Error Unable to find source space home xxx src 在新建的工作空间下进行 catkin build 编译工作空间 xff0c 工作空间下没有产生 devel logs b
  • Geometrically Constrained Trajectory Optimization for Multicopters 论文解析

    关于多旋翼几何约束轨迹优化 MINCO 轨迹类几何约束实验 Geometrically Constrained Trajectory Optimization for Multicopters 一文由浙江大学博士 汪哲培 2022年发表在I
  • Fast-planner 和 Ego-planner 比较

    Fast planner 和 Ego planner 比较 Fast PlannerEgo planner Fast planner和Ego planner都是无人机路径规划中常见的算法 xff0c 但它们的实现方式和目标略有不同 Fast
  • Teach-Repeat-Replan: A Complete and Robust System for Aggressive Flight in Complex Environments 论文笔记

    Teach Repeat Replan 飞行走廊生成方法凸多面体膨胀CPU加速GPU加速飞行走廊生成与环路消除 时空全局轨迹优化空间轨迹优化时间轨迹优化 在线局部重规划局部重规划框架 飞行走廊生成方法 围绕 teaching traject
  • ovn实验手册

    参考文档 openstack ovn结合官方文档 ovn实践参考
  • 蓝桥杯 小数第n位 问题的几种解法

    蓝桥杯 小数第n位 问题的几种解法 题目描述解法1 根据手动计算除法的过程 题目描述 我们知道 xff0c 整数做除法时 xff0c 有时得到有限小数 xff0c 有时得到无限循环小数 如果我们把有限小数的末尾加上无限多个 0 xff0c
  • 解决Vmware虚拟机无法打开Ubuntu的问题

    1 xff0c 问题 很多同学会在Window PC机上使用Vmware虚拟机来搭建Linux开发环境 xff08 如Ubuntu xff09 xff0c 使用过程中难免会出现Ubuntu崩溃 异常关闭等现象 xff0c 此时 xff0c
  • antd 表单动态添加表单项编辑回显数据

    在做一些后台管理会用到很多的表单 xff0c 比如动态项表单 xff0c 如下图这样的 话不多说 xff0c 上代码 创建修改版本 import React from 34 react 34 import Form Notification
  • 二进制流文件下载

    在做一些文件下载的时候 xff0c 后端返回的二进制流文件 xff0c 这里前端的兄弟姐妹就需要处理一下了 直接上代码 xff1a 下载 export function download id return request url 96 r
  • ES6数组reduce的妙用

    定义和用法 reduce 方法接收一个函数作为累加器 xff0c 数组中的每个值 xff08 从左到右 xff09 开始缩减 xff0c 最终计算为一个值 reduce 可以作为一个高阶函数 xff0c 用于函数的 compose 注意 r
  • element 去掉form表单的某一项单个form-Item校验

    在执行完相应的方法 xff0c 立即触发移除校验 this nextTick 61 gt this refs 39 form 39 clearValidate 39 name 39 this refs 39 form 39 clearVal
  • element表单多行数据自定义校验以及自定义传参

    场景说明 如下图 在form表单中迁移table表格 每行数据都要能编辑 单独校验 注释 此处的资源下拉框校验 还需要走异步请求获取结果 然后再对比校验 nbsp 话不多 上代码说明 1 首先获取的接口数据如下 form vmDataLis
  • Hbuilder修改项目git提交路径

    在git的使用中 xff0c 经常会出现git服务器IP地址变更的现象 xff0c 一旦服务器的IP地址有变化 xff0c 本地仓库的代码就和服务器失去了联系 xff0c 无法同步服务器的代码 这里说明一下 xff0c 如何修改git提交路
  • css3的clip-path方法剪裁实现(三角形,多边形,圆,椭圆)

    本例讲解如何通过clip path 把一个div xff08 元素 xff0c 可以是图片等 xff09 裁切成不同的形状 xff0c 这里以一个div为例宽高均为300px 注意 xff1a 不支持IE和Firefox xff0c 支持w
  • layui表格(table)排序

    layui表格本身提供sort排序 xff0c 但是只能排序当前一页 xff1b 如果后台返回几十页数据 xff0c 需要排序显示 xff0c 该如何做呢 xff0c 这里闲心大神提供了一个sort监听方法 xff1a 通过监听排序的列 x
  • Liunx下修改MySQL字符集

    Liunx下修改MySQL字符集 1 查找MySQL的cnf文件的位置 color 61 green find iname 39 cnf 39 print color color 61 olive usr share mysql my in
  • vue刷新当前页面,重载页面数据

    业务场景 xff1a 在管理后台 xff0c 在执行完 xff0c 增 xff0c 删 xff0c 改 xff0c 操作的时候 我们需要刷新一下页面 xff0c 重载数据 在JQ中我们会用到location reload 方法 xff0c
  • layui动态渲染生成左侧3级菜单(根据后台返回数据)

    声明 xff1a 这里非常感谢闲心大神 xff0c 开源了非常好用的前端UI框架 xff0c layui xff0c 如有侵权请联系我 当然闲心在2 0版本的layuiAdmin已经支持了 xff0c 不过是收费版的 xff0c 需要的同学