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


Posted in Javascript onSeptember 23, 2019

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

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

layui动态渲染生成左侧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" rel="external nofollow" >
<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:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" >' + 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:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" >' + 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 +'" rel="external nofollow" >' + grandsonNodes[k].title + '</a>';
    ulHtml += '</dd>';
    }
   ulHtml += '</dl>';
   ulHtml += '</dd>';
   }else{
   ulHtml += '<dd>';
   ulHtml += '<a href="'+data[i].children[j].href+'" rel="external nofollow" >' + 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:;" rel="external nofollow" rel="external nofollow" rel="external nofollow" ' + dataUrl + '>';
  ulHtml += '<a href="' + data[i].href + '" rel="external nofollow" ' + 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循环,遍历后台返回的数据。

以上这篇layui动态渲染生成左侧3级菜单的方法(根据后台返回数据)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery学习基础知识小结
Nov 25 Javascript
jQuery(非HTML5)可编辑表格实现代码
Dec 11 Javascript
jquery $.trim()方法使用介绍
May 21 Javascript
Bootstrap3 Grid system原理及应用详解
Sep 30 Javascript
javascript判断回文数详解及实现代码
Feb 03 Javascript
vue自动化表单实例分析
May 06 Javascript
electron中使用bootstrap的示例代码
Nov 06 Javascript
微信小程序实现复选框效果
Dec 28 Javascript
如何在postman中添加cookie信息步骤解析
Jun 30 Javascript
JS常见错误(Error)及处理方案详解
Jul 02 Javascript
vue-quill-editor 自定义工具栏和自定义图片上传路径操作
Aug 03 Javascript
详解vue父子组件状态同步的最佳方式
Sep 10 Javascript
layui树形菜单动态遍历的例子
Sep 23 #Javascript
Vue+elementui 实现复杂表头和动态增加列的二维表格功能
Sep 23 #Javascript
优雅的使用javascript递归画一棵结构树示例代码
Sep 22 #Javascript
Webpack按需加载打包chunk命名的方法
Sep 22 #Javascript
jquery.tagsinput.js实现记录checkbox勾选的顺序
Sep 21 #jQuery
vue2.0+SVG实现音乐播放圆形进度条组件
Sep 21 #Javascript
js+springMVC 提交数组数据到后台的实例
Sep 21 #Javascript
You might like
PHP启动windows应用程序、执行bat批处理、执行cmd命令的方法(exec、system函数详解)
2014/10/20 PHP
AES加解密在php接口请求过程中的应用示例
2016/10/26 PHP
PHP中Session ID的实现原理实例分析
2019/08/17 PHP
JQuery 学习笔记 element属性控制
2009/07/23 Javascript
jquery 分页控件实现代码
2009/11/30 Javascript
分享一道笔试题[有n个直线最多可以把一个平面分成多少个部分]
2012/10/12 Javascript
判定是否原生方法的JS代码
2013/11/12 Javascript
jQuery基础语法实例入门
2014/12/23 Javascript
jQuery实现鼠标滑过Div层背景变颜色的方法
2015/02/17 Javascript
详解JavaScript中的every()方法
2015/06/08 Javascript
jQuery搜索框效果实现代码(百度关键词联想)
2021/02/25 Javascript
jQuery实现智能判断固定导航条或侧边栏的方法
2016/09/04 Javascript
JS中常用的正则表达式
2016/09/29 Javascript
Bootstrap免费字体和图标网站(值得收藏)
2017/03/16 Javascript
vue项目中api接口管理总结
2018/04/20 Javascript
Angular4.x通过路由守卫进行路由重定向实现根据条件跳转到相应的页面(推荐)
2018/05/10 Javascript
vue异步axios获取的数据渲染到页面的方法
2018/08/09 Javascript
详解js中的原型,原型对象,原型链
2020/07/16 Javascript
解决Vue中的生命周期beforeDestory不触发的问题
2020/07/21 Javascript
vue实现lodop打印功能的示例
2020/11/11 Javascript
vue 使用rules对表单字段进行校验的步骤
2020/12/25 Vue.js
Python魔术方法详解
2015/02/14 Python
Python使用pymysql从MySQL数据库中读出数据的方法
2018/07/25 Python
Python3 Tkinter选择路径功能的实现方法
2019/06/14 Python
scikit-learn线性回归,多元回归,多项式回归的实现
2019/08/29 Python
jupyter notebook 多环境conda kernel配置方式
2020/04/10 Python
Python编写万花尺图案实例
2021/01/03 Python
德国户外装备、登山运动和攀岩商店:tapir store
2020/02/12 全球购物
2014道德模范事迹材料
2014/02/16 职场文书
手机被没收检讨书
2014/02/22 职场文书
工地安全质量标语
2014/06/07 职场文书
环境建议书
2015/02/04 职场文书
博士论文答辩开场白
2015/06/01 职场文书
音乐课《小猫钓鱼》教学反思
2016/02/18 职场文书
pytorch显存一直变大的解决方案
2021/04/08 Python
web前端之css水平居中代码解析
2021/05/20 HTML / CSS