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 相关文章推荐
ExtJS 学习专题(一) 如何应用ExtJS(附实例)
Mar 11 Javascript
JavaScript 弹出窗体点击按钮返回选择数据的实现
Apr 01 Javascript
关于Javascript模块化和命名空间管理的问题说明
Dec 06 Javascript
JQuery为页面Dom元素绑定事件及解除绑定方法
Apr 23 Javascript
Angularjs制作简单的路由功能demo
Apr 14 Javascript
BootStrap3中模态对话框的使用
Jan 06 Javascript
jQuery动态生成表格及右键菜单功能示例
Jan 13 Javascript
Reactjs实现通用分页组件的实例代码
Jan 19 Javascript
webpack+react+antd脚手架优化的方法
Apr 02 Javascript
trackingjs+websocket+百度人脸识别API实现人脸签到
Nov 26 Javascript
微信小程序点击图片实现长按预览、保存、识别带参数二维码、转发等功能
Jul 20 Javascript
基于js实现数组相邻元素上移下移
May 19 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
MVC模式的PHP实现
2006/10/09 PHP
基于mysql的论坛(7)
2006/10/09 PHP
PHP 生成的XML以FLASH获取为乱码终极解决
2009/08/07 PHP
PHP XML操作的各种方法解析(比较详细)
2010/06/17 PHP
PHP实现QQ空间自动回复说说的方法
2015/12/02 PHP
PHP给源代码加密的几种方法汇总(推荐)
2018/02/06 PHP
JQuery 1.6发布 性能提升,同时包含大量破坏性变更
2011/05/10 Javascript
JS注释所产生的bug 即使注释也会执行
2013/11/19 Javascript
深入分析JSONP跨域的原理
2014/12/10 Javascript
jQuery3.0中的buildFragment私有函数详解
2016/08/16 Javascript
Angularjs 创建可复用组件实例代码
2016/10/09 Javascript
angularjs中使用ng-bind-html和ng-include的实例
2017/04/28 Javascript
vue左右侧联动滚动的实现代码
2018/06/06 Javascript
小程序扫描普通链接二维码跳转小程序指定界面方法
2019/05/07 Javascript
vue 实现通过vuex 存储值 在不同界面使用
2019/11/11 Javascript
javascript设计模式 ? 装饰模式原理与应用实例分析
2020/04/14 Javascript
基于JQuery实现页面定时弹出广告
2020/05/08 jQuery
Python最基本的数据类型以及对元组的介绍
2015/04/14 Python
Python易忽视知识点小结
2015/05/25 Python
Python2.x与Python3.x的区别
2016/01/14 Python
一些常用的Python爬虫技巧汇总
2016/09/28 Python
Python中第三方库Requests库的高级用法详解
2017/03/12 Python
基于Python函数和变量名解析
2019/07/19 Python
搭建pypi私有仓库实现过程详解
2020/11/25 Python
CSS3下的渐变文字效果实现示例
2018/03/02 HTML / CSS
HTML5 Canvas的事件处理介绍
2015/04/24 HTML / CSS
Johnston & Murphy官网: 约翰斯顿·墨菲牛津总统鞋
2018/01/09 全球购物
运动会稿件100字
2014/02/21 职场文书
安全教育月活动总结
2014/05/05 职场文书
求职推荐信范文
2015/03/27 职场文书
关爱留守儿童捐款倡议书
2015/04/27 职场文书
学校财务管理制度
2015/08/04 职场文书
2015年店长个人工作总结
2015/10/23 职场文书
《我和小伙伴》教学反思
2016/02/20 职场文书
Python编写nmap扫描工具
2021/07/21 Python
梳理总结Python开发中需要摒弃的18个坏习惯
2022/01/22 Python