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.autocomplete修改实现键盘上下键自动填充示例
Nov 19 Javascript
js实现仿阿里巴巴城市选择框效果实例
Jun 24 Javascript
js模拟淘宝网的多级选择菜单实现方法
Aug 18 Javascript
Javascript控制div属性动态变化实例分析
Oct 08 Javascript
使用javaScript动态加载Js文件和Css文件
Oct 24 Javascript
jQuery的promise与deferred对象在异步回调中的作用
May 03 Javascript
jquery实现全选和全不选功能效果的实现代码【推荐】
May 05 Javascript
详解JavaScript对象类型
Jun 16 Javascript
详解JavaScript节流函数中的Throttle
Jul 16 Javascript
JS验证字符串功能
Feb 22 Javascript
JavaScript实现更换背景图片
Oct 18 Javascript
在vue中封装的弹窗组件使用队列模式实现方法
Jul 23 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 创建文件(文件夹)以及目录操作代码
2010/03/04 PHP
php读取富文本的时p标签会出现红线是怎么回事
2014/05/13 PHP
简单谈谈PHP中的include、include_once、require以及require_once语句
2016/04/23 PHP
PHP简单预防sql注入的方法
2016/09/27 PHP
不用ajax实现点击文字即可编辑的方法
2007/12/16 Javascript
javascript 尚未实现错误解决办法
2008/11/27 Javascript
HTA版JSMin(省略修饰语若干)基于javascript语言编写
2009/12/24 Javascript
setTimeout与setInterval在不同浏览器下的差异
2010/01/24 Javascript
在标题栏显示新消息提示,很多公司项目中用到这个方法
2011/11/04 Javascript
基于iframe实现类似于ajax的页面无刷新
2014/05/31 Javascript
JavaScript获取按钮所在form表单id的方法
2015/04/02 Javascript
js漂浮广告实现代码
2015/08/15 Javascript
分享网页检测摇一摇实例代码
2016/01/14 Javascript
Vue官方文档梳理之全局配置
2017/11/22 Javascript
使用vue点击li,获取当前点击li父辈元素的属性值方法
2018/09/12 Javascript
vue如何在项目中调用腾讯云的滑动验证码
2020/07/15 Javascript
vue 子组件修改data或调用操作
2020/08/07 Javascript
js 将多个对象合并成一个对象 assign方法的实现
2020/09/24 Javascript
使用cx_freeze把python打包exe示例
2014/01/24 Python
举例讲解Python中的迭代器、生成器与列表解析用法
2016/03/20 Python
python实现微信机器人: 登录微信、消息接收、自动回复功能
2019/04/29 Python
Pandas之Dropna滤除缺失数据的实现方法
2019/06/25 Python
使用python来调用CAN通讯的DLL实现方法
2019/07/03 Python
python selenium 执行完毕关闭chromedriver进程示例
2019/11/15 Python
OpenCV 表盘指针自动读数的示例代码
2020/04/10 Python
森海塞尔美国官网:Sennheiser耳机与耳麦
2017/07/19 全球购物
L’AGENCE官网:加州女装品牌
2018/06/03 全球购物
Java编程面试题
2016/04/04 面试题
结婚典礼证婚词
2014/01/08 职场文书
美术国培研修感言
2014/02/12 职场文书
春节联欢晚会主持词
2014/03/24 职场文书
工商干部先进事迹
2014/05/14 职场文书
大学生村官考核材料
2014/05/23 职场文书
公司董事长助理工作职责
2014/07/12 职场文书
《中国梦我的梦》中学生演讲稿
2014/08/20 职场文书
2016年第二十届“母亲节暨幸福工程救助贫困母亲活动日”活动总结
2016/04/06 职场文书