最近看了一篇关于JSON无限折叠菜单的文章 感觉写的不错,也研究了下代码,自己也实际应用到公司项目里了,很实用,推荐一下.
推荐地址:http://www.cnblogs.com/tugenhua0707/p/3474791.html
/**
* JSON无限折叠菜单
* @constructor {AccordionMenu}
* @param {options} 对象
*/
function AccordionMenu(options) {
this.config = {
containerCls : '.wrap-menu', // 外层容器
menuArrs : '', // JSON传进来的数据
type : 'click', // 默认为click 也可以mouseover
renderCallBack : null, // 渲染html结构后回调
clickItemCallBack : null // 每点击某一项时候回调
};
this.cache = {
};
this.init(options);
}
AccordionMenu.prototype = {
constructor: AccordionMenu,
init: function(options){
this.config = $.extend(this.config,options || {});
var self = this,
_config = self.config,
_cache = self.cache;
// 渲染html结构
$(_config.containerCls).each(function(index,item){
self._renderHTML(item);
// 处理点击事件
self._bindEnv(item);
});
},
_renderHTML: function(container){
var self = this,
_config = self.config,
_cache = self.cache;
var ulhtml = $('
');
$(_config.menuArrs).each(function(index,item){
var lihtml = $(''+item.name+'
');
if(item.submenu && item.submenu.length > 0) {
self._createSubMenu(item.submenu,lihtml);
}
$(ulhtml).append(lihtml);
});
$(container).append(ulhtml);
_config.renderCallBack && $.isFunction(_config.renderCallBack) && _config.renderCallBack();
// 处理层级缩进
self._levelIndent(ulhtml);
},
/**
* 创建子菜单
* @param {array} 子菜单
* @param {lihtml} li项
*/
_createSubMenu: function(submenu,lihtml){
var self = this,
_config = self.config,
_cache = self.cache;
var subUl = $('
'),
callee = arguments.callee,
subLi;
$(submenu).each(function(index,item){
var url = item.url || 'javascript:void(0)';
subLi = $(''+item.name+' ');
if(item.submenu && item.submenu.length > 0) {
$(subLi).children('a').prepend('');
callee(item.submenu, subLi);
}
$(subUl).append(subLi);
});
$(lihtml).append(subUl);
},
/**
* 处理层级缩进
*/
_levelIndent: function(ulList){
var self = this,
_config = self.config,
_cache = self.cache,
callee = arguments.callee;
var initTextIndent = 2,
lev = 1,
$oUl = $(ulList);
while($oUl.find('ul').length > 0){
initTextIndent = parseInt(initTextIndent,10) + 2 + 'em';
$oUl.children().children('ul').addClass('lev-' + lev)
.children('li').css('text-indent', initTextIndent);
$oUl = $oUl.children().children('ul');
lev++;
}
$(ulList).find('ul').hide();
$(ulList).find('ul:first').show();
},
/**
* 绑定事件
*/
_bindEnv: function(container) {
var self = this,
_config = self.config;
$('h2,a',container).unbind(_config.type);
$('h2,a',container).bind(_config.type,function(e){
if($(this).siblings('ul').length > 0) {
$(this).siblings('ul').slideToggle('slow').end().children('img').toggleClass('unfold');
}
$(this).parent('li').siblings().find('ul').hide()
.end().find('img.unfold').removeClass('unfold');
_config.clickItemCallBack && $.isFunction(_config.clickItemCallBack) && _config.clickItemCallBack($(this));
});
}
};
.wrap-menu {
overflow:auto;
width:300px;
background:#F6F6F6;
font:12px/1.5 Tahoma,Arial,sans-serif
}
.wrap-menu ul {
list-style:none;
margin:0;
padding:0;
}
.wrap-menu ul li {
text-indent:3em;
white-space:nowrap;
}
.wrap-menu ul li h2 {
cursor:pointer;
height:100%;
width:100%;
margin:0 0 1px 0;
font:12px/31px '宋体';
color:#fff;
background:red;
}
.wrap-menu ul li a {
display:block;
outline:none;
height:25px;
line-height:25px;
margin:1px 0;
color:#1A385C;
text-decoration:none;
}
.wrap-menu ul li img {
margin-right:10px;
margin-left:-17px;
margin-top:9px;
width:7px;
height:7px;
background:url(images/arrow.gif) no-repeat;
border:none;
}
.wrap-menu ul li img.unfold {
background-position:0 -9px;
}
.wrap-menu ul li a:hover {
background-color:#ccc;
background-image:none;
}
$(function(){
new AccordionMenu({menuArrs:testMenu});
});
提示:
new AccordionMenu({menuArrs:testMenu}); 其中testMenu 就是下面定义的JSON格式
var testMenu=[
{
"name": "一级菜单",
"submenu": [
{
"name": "二级菜单",
"url": ""
},
{
"name": "二级菜单",
"url": ""
}
]
},
{
"name": "一级菜单",
"submenu": [
{
"name": "二级菜单",
"url": ""
},
{
"name": "二级菜单",
"submenu": [
{
"name": "三级菜单",
"submenu": [
{
"name": "四级菜单",
"url": ""
}
]
},
{
"name": "三级菜单",
"url": ""
}
]
},
{
"name": "二级菜单",
"url": ""
},
{
"name": "二级菜单",
"submenu": [
{
"name": "三级菜单",
"submenu": [
{
"name": "四级菜单",
"url": ""
},
{
"name": "四级菜单",
"submenu": [
{
"name": "五级菜单",
"url": ""
},
{
"name": "五级菜单",
"url": ""
}
]
}
]
},
{
"name": "三级菜单",
"url": ""
}
]
},
{
"name": "二级菜单",
"url": ""
}
]
},
{
"name": "一级菜单",
"submenu": [
{
"name": "二级菜单",
"url": ""
},
{
"name": "二级菜单",
"url": ""
},
{
"name": "二级菜单",
"url": ""
}
]
}
];
为了方便,自行写了Java无限菜单递归封装的代码以及无限菜单代码,如下:
/**
* 初始化加载菜单,获取菜单列表
*
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(value = "/getMenuList", method = RequestMethod.POST, produces = {
"application/json; charset=UTF-8"})
public Object getMenuList(@RequestBody JSONObject jsonP) throws Exception {
JSONArray menuArray = new JSONArray();
JSONObject menuList = new JSONObject();
JSONObject menuObject = new JSONObject();
List menuListAll = iMenuService.getMenuList();
JSONArray menuArrayAll = JSONArray.parseArray(JSONArray.toJSONString(menuListAll));
if (menuArrayAll != null && !menuArrayAll .isEmpty()) {
for (int i = 0; i < menuArrayAll.size(); i++) {
JSONObject jsonObj = menuArrayAll.getJSONObject(i);
JSONArray menuItems = menuObject.getJSONArray(jsonObj.getString("menuTid"));
if (menuItems == null || menuItems.isEmpty()) {
JSONArray jsonArr = new JSONArray();
jsonArr.add(jsonObj);
menuObject.put(jsonObj.getString("menuTid"), jsonArr);
} else {
menuItems.add(jsonObj);
menuObject.put(jsonObj.getString("menuTid"), menuItems);
}
JSONObject menu = new JSONObject();
menu.put("idx", i + 1); // 序号
menu.put("id", jsonObj.getString("menuPid")); // ID
menu.put("name", jsonObj.getString("menuName"));
menuArray.add(menu);
}
}
menuList.put("menuList", getMenuListByTid(menuObject, jsonP.getIntValue("menuTid")));
menuList.put("mArray", menuArray);
return menuList;
}
/**
* 递进菜单列表
*
* @param menuTid
* @return
*/
private JSONArray getMenuListByTid(JSONObject menuObject, Integer menuTid) {
JSONArray menuArray = new JSONArray();
JSONArray menuList = menuObject.getJSONArray(menuTid.toString());
if (menuList != null && !menuList.isEmpty()) {
for (int i = 0; i < menuList.size(); i++) {
JSONObject menuItem = new JSONObject();
TbMenu tbMenu = menuList.getObject(i, TbMenu.class);
menuItem.put("name", tbMenu.getMenuName()); // 菜单名称
JSONArray menuListItem = menuObject.getJSONArray(tbMenu.getMenuPid().toString());
if (menuListItem == null || menuListItem.isEmpty()) {
menuItem.put("target", tbMenu.getMenuTarget()); // 跳转方式
menuItem.put("url", tbMenu.getMenuUrl()); // 访问url
} else {
menuItem.put("submenu", getMenuListByTid(menuObject, tbMenu.getMenuPid()));
}
menuArray.add(menuItem);
}
}
return menuArray;
}
/*
* metismenu - v1.1.3
* Easy menu jQuery plugin for Twitter Bootstrap 3
* https://github.com/onokumus/metisMenu
*
* Made by Osman Nuri Okumus
* Under MIT License
*/
;(function ($, window, document, undefined) {
// 数据初始化
var menuDatas = null;
$.ajax({
url: "/menu/getMenuList",
type: "POST",
data: JSON.stringify({"menuTid": 0}), //传参为0,加载根(一级)菜单,1加载二级菜单,2加载三级菜单...
dataType: "json",
async: false, //开启同步,先加载完ajax请求,再继续往下执行菜单渲染代码
contentType: "application/json",
success: function (menuData) {
// console.log("成功:" + JSON.stringify(menuData));
menuDatas = JSON.stringify(menuData.menuList);
},
error: function (msg) {
console.log("失败:" + msg);
}
});
var renderCallBack = null;
// 渲染html结构
$(".sidebar-collapse").each(function (index, item) {
_renderHTML(item);
});
/**
* 创建主菜单
* @param {array} 主菜单
* @param {lihtml} li项
*/
function _renderHTML(container) {
var ulhtml = $(''
+ 'D+ ');
$(ulhtml).append(liheader);
$(menuDatas).each(function (index, item) {
var url = (item.url) || ('/?path=welcome&random=' + Math.random());
if (item.submenu && item.submenu.length > 0) {
lihtml = $(''
+ ' '
+ ((item.submenu && item.submenu.length > 0) ? '' : '')
+ ' ');
_createSubMenu(item.submenu, lihtml);
} else if (item.target && item.target.length > 0) {
lihtml = $(''
+ ' ');
} else {
lihtml = $(''
+ ' ');
}
$(ulhtml).append(lihtml);
});
$(container).append(ulhtml);
renderCallBack && $.isFunction(renderCallBack) && renderCallBack();
}
/**
* 创建子菜单
* @param {array} 子菜单
* @param {lihtml} li项
*/
function _createSubMenu(children, lihtml) {
var subUl = $(' '),
callee = arguments.callee,
subLi;
$(children).each(function (index, item) {
var url = (item.url) || ('/?path=welcome&random=' + Math.random());
if (item.submenu && item.submenu.length > 0) {
subLi = $(' '
+ ((item.submenu && item.submenu.length > 0) ? '' : '')
+ ' ');
callee(item.submenu, subLi);
} else if (item.target && item.target.length > 0) {
subLi = $('' + item.name + ' ');
} else {
subLi = $('' + item.name + ' ');
}
$(subUl).append(subLi);
});
$(lihtml).append(subUl);
// 处理层级缩进
_levelIndent(subUl);
}
/**
* 处理层级缩进
*/
function _levelIndent(ulList) {
var lev = 1,
$oUl = $(ulList);
while ($oUl.find('ul').length > 0) {
$oUl.children().children('ul').addClass("coll");
$oUl = $oUl.children().children('ul');
lev++;
}
$(ulList).find('ul').slideUp(200);
// $(ulList).find('ul:first').slideUp(200);
}
var pluginName = "metisMenu",
defaults = {
toggle: true,
doubleTapToGo: false
};
function Plugin(element, options) {
this.element = $(element);
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype = {
init: function () {
if (menuDatas.length == 0) {
return;
}
var $this = this.element,
$toggle = this.settings.toggle,
obj = this;
if (this.isIE() <= 9) {
$this.find("li.active").has("ul").children("ul").collapse("show");
$this.find("li").not(".active").has("ul").children("ul").collapse("hide");
} else {
$this.find("li.active").has("ul").children("ul").addClass("collapse in");
$this.find("li").not(".active").has("ul").children("ul").addClass("collapse");
}
//add the "doubleTapToGo" class to active items if needed
if (obj.settings.doubleTapToGo) {
$this.find("li.active").has("ul").children("a").addClass("doubleTapToGo");
}
$this.find("li").has("ul").children("a").on("click" + "." + pluginName, function (e) {
e.preventDefault();
//Do we need to enable the double tap
if (obj.settings.doubleTapToGo) {
//if we hit a second time on the link and the href is valid, navigate to that url
if (obj.doubleTapToGo($(this)) && $(this).attr("href") !== "#" && $(this).attr("href") !== "") {
e.stopPropagation();
document.location = $(this).attr("href");
return;
}
}
$(this).parent("li").toggleClass("active").children("ul").collapse("toggle");
if ($toggle) {
$(this).parent("li").siblings().removeClass("active").children("ul.in").collapse("hide");
}
});
},
isIE: function () { //https://gist.github.com/padolsey/527683
var undef,
v = 3,
div = document.createElement("div"),
all = div.getElementsByTagName("i");
while (
div.innerHTML = "",
all[0]
) {
return v > 4 ? v : undef;
}
},
//Enable the link on the second click.
doubleTapToGo: function (elem) {
var $this = this.element;
//if the class "doubleTapToGo" exists, remove it and return
if (elem.hasClass("doubleTapToGo")) {
elem.removeClass("doubleTapToGo");
return true;
}
//does not exists, add a new class and return false
if (elem.parent().children("ul").length) {
//first remove all other class
$this.find(".doubleTapToGo").removeClass("doubleTapToGo");
//add the class on the current element
elem.addClass("doubleTapToGo");
return false;
}
},
remove: function () {
this.element.off("." + pluginName);
this.element.removeData(pluginName);
}
};
$.fn[pluginName] = function (options) {
this.each(function () {
var el = $(this);
if (el.data(pluginName)) {
el.data(pluginName).remove();
}
el.data(pluginName, new Plugin(this, options));
});
return this;
};
})(jQuery, window, document);
'),
lihtml;
var liheader = $('
转载请注明出处!