1 自定义菜单导航栏插件的必要性

  看图说话,下面是利用自定义的菜单导航栏插件simpleMenu创建的网站导航示例:

  

  插件默认提供的是如上图的导航栏样式,即一二级菜单为横向分布;三四级菜单为纵向分布。

  使用插件时,可以修改默认参数,目前插件提供了设置菜单的分布方式:横向或纵向;菜单的位置:依赖上一级菜单栏的定位:上下左右定位。

  修改调用参数,将一二级菜单改为纵向排列;并将三级菜单的显示位置改为二级菜单栏的右侧(其他的和默认保持一致),修改后运行效果如下图:

  

  细心的观察,会发现上面两个菜单导航栏的风格基本一致,只是在局部有所调整。之所以这样设计,是因为随着网站的逐渐丰富,菜单导航栏的需求也会经常发生变化。通过参数化配置菜单,能够在现有的基础上,快速适应新的变化。当然这样做也会对我们编写插件提出更要的要求和更大的挑战,况且始终无法做一个万能的菜单出来!

2 使用jQuery UI的Widget库自定义菜单导航栏插件

  jQuery UI的功能很强大,主要分为3个部分:交互、微件(Widget)和效果库。其中交互是一些与鼠标交互的内容如拖动、缩放、选择和排序等;微件主要是一些节目的扩展包括对话框、日历、进度条,当然也有类似的菜单导航;效果库是用于提供丰富的动画效果,让动画不在局限于animate方法。

  虽然jQuery UI已经提供了类似导航的功能,但其功能和效果往往难以满足复杂项目的需求。下面说说重点,我所希望实现的插件功能是:插件对外提供创建菜单的接口函数,输入参数为包含菜单项信息的数据源,输出为对应的多级菜单。利用jQuery UI的Widget库,我们可以轻松自定义新的jQuery UI微件,满足上述功能需求。

2.1 创建Widget插件

  通过Widget Factory创建微件的方法是向$.widget()传递一个widget的名称和原型对象。例如在菜单导航栏插件中,定义方式如下:  

var menu = $.widget('myPlugin.simpleMenu', {
version: "1.0.1",
pathPrefix: $.myPlugin.config.pathPrefix,
options: {
/*default params*/
}, _create: function () { },
/*具体实现函数略*/
_destroy: function() { },
});

  这里在myPlugin命名空间下定义了一个名为simpleMenu的Widget,即菜单导航栏插件。在给定的原型对象中还定义了插件的版本,路径前缀,默认参数,创建函数,实现函数等。要注意的是,Widget插件的真正创建时从_create开始的,这个函数我们可以重写覆盖,至于内部是怎么调用的这个过程插件对我们透明。

2.2 需要实现的具体功能

  之前已经说了,菜单导航栏插件的输入数据为包含菜单项信息的数据源。考虑到通用性,推荐使用JSON作为数据源。JSON数据的组装以及读取都很简单,难点在于如何将JSON数据转换为任意层次的菜单,并且保证菜单每一级菜单项都能正确地绑定监听事件(鼠标点击或鼠标经过、离开等事件)。

  生成的菜单导航和原始的JSON数据都是具有层次结构的,为了生成与JSON层次相同的菜单层次,最简单有效的方法就是递归调用。然而多级菜单的递归调用并不是一次成型的,而是按需调用——用户点击或经过某个菜单项时才触发一次递归调用。下面首先贴出createMenu的代码,这段代码主要实现的就是根据menuList(待加载的菜单项集合)和menuPath(上一级菜单项的路径)来加载当前菜单项集合。例如第一次执行该函数时,menuList为原始的菜单项-JSON数组,menuPath为"item"-顶层初始值;遍历menuList的每个元素(对应一级菜单的菜单项),首先生成带初始样式的html结构;然后设置当前级别(如一级)菜单的状态,包括在文档中的位置,绑定事件,以及在菜单项过多的时候及时提供滚动换页功能;递归在绑定事件函数中产生,当用户触发绑定事件时,会调用createMenu函数,并传递两个参数:触发菜单项的下级菜单集合以及路径信息。

  createMenu私有函数的实现如下:

_createMenu: function(menuList, menuPath){
var pathArr = menuPath.split('-'),
level = pathArr.length,
menuClass = ".menu" + level,
menuDiv,
menuUl,
content = "",
menuSubflag,
menuName,
menuItem; if((menuDiv = this.element.find(menuClass)).length === 0){
return;
}
menuUl = menuDiv.children("ul"); /*循环生成level级菜单的html代码并添加到菜单ul中*/
for(var i = 0, len = menuList.length; i < len; i++){
menuItem = menuList[i];
menuName = menuItem.menuName;
menuSubflag = ""; /*判断菜单项是否为叶子菜单(不含子菜单)*/
if(menuItem.subMenu && menuItem.subMenu.length > 0){
if(level > 1){
menuName += "<div class='sub'></div>";
}
}
else{
menuSubflag = " class = 'leaf'";
} content += "<li data-path='" + menuPath + "-" + (i + 1) + "'" +
menuSubflag + ">" + menuName + "</li>";
}
menuUl.html(content);
menuDiv.show(); /*显示当前的菜单栏(有些菜单栏默认设置为隐藏)*/ /*设置level级菜单栏的位置*/
this._setPosition(pathArr, menuDiv); /*绑定菜单鼠标点击或经过事件*/
this._bindMenuEvents(menuList, menuUl, level); /*设置菜单的水平滚动*/
this._setMenuScroll();
}

  绑定菜单项事件函数如下:

/*菜单事件函数,处理菜单的点击或鼠标经过事件*/
_bindMenuEvents: function(menuList, menuUl, level){
/*记录当前的this指针,以便在绑定函数内部使用*/
var that = this; /*给菜单项绑定鼠标事件-鼠标点击或是鼠标经过事件*/
menuUl.children("li").bind(this.options.menuEvents[level - 1],
(function(menuList){
return function(){
$(this).addClass('select').siblings().removeClass('select'); var subMenu = menuList[$(this).index()].subMenu;
that._createMenu(subMenu, $(this).attr("data-path"));
}
})(menuList)); /*给叶子菜单项绑定鼠标点击事件-执行跳转(一级菜单不执行跳转)*/
if(level <= 1){
return;
}
menuUl.children("li.leaf").click(function(menuList){
return function(){
var menuItem = menuList[$(this).index()];
that._executeMenu(menuItem);
};
}(menuList));
}

  上面的代码实现了任意级菜单的动态生成。接下来需要做的只是在此基础上丰富插件,增加灵活性。后续开发中,我增加了设置菜单排列方向的功能:比如设置一级菜单横向或纵向排列;还增加了菜单定位功能:比如生成的二级菜单相对于触发它的一级菜单项的位置靠右或正下方显示。

  在提供额外功能的同时,也面临更多的问题:首先这些功能增加了使用者的学习成本,其次有些功能如菜单定位中存在一些并不合理的设置。这些都期待在以后不断完善!

3 插件使用方法

  插件的使用方法:首先需要提供一个格式正确的JSON菜单数据,目前自定义的插件在处理时主要依据JSON中的menuName、subMenu、actionList等key来取得实际的value值,所以提供的JSON数据必须类似下面的例子形式。然后使用插件名来调用插件时:注意在插件参数中除了提供菜单的基本信息外,还可以指定一个回调函数来处理链接的跳转;通过回调函数实现了菜单生成插件本身与执行跳转逻辑的解耦,方便使用者根据实际情况编写回调函数来选择跳转的方式

$(document).ready(function(){
var menuJson =
[
{"menuName": "导航菜单栏目1", "menuCode": "", "subMenu":
[
{"menuName": "二级菜单1", "menuCode": "", "subMenu":
[
{"menuName": "三级菜单1", "menuCode": "", "subMenu":
[
{"menuName": "四级菜单1", "menuCode": "", "actionList": "www.abchina.com", "subMenu": []}
]
},
{"menuName": "三级菜单2", "menuCode": "", "subMenu":
[
{"menuName": "四级菜单1", "menuCode": "", "subMenu": []}
]
}
]
},
{"menuName": "二级菜单2", "menuCode": "", "subMenu": []}
]
},
{"menuName": "导航菜单栏目2", "menuCode": "", "subMenu":
[
{"menuName": "二级菜单3", "menuCode": "", "subMenu":
[
{"menuName": "三级菜单3", "menuCode": "", "subMenu": []}
]
},
{"menuName": "二级菜单4", "menuCode": "", "subMenu": []}
]
},
{"menuName": "导航菜单栏目3", "menuCode": "", "subMenu":
[
{"menuName": "二级菜单5", "menuCode": "", "subMenu": []}
]
}
]; $(".menu").simpleMenu({menuList: menuJson, executeMenu: function(actionList){
window.location.href = actionList;
}});
});

  本博文为个人原创作品,转载时请注明出处。如有建议,请直接回帖交流,谢谢!

jquery自定义插件-参数化配置多级菜单导航栏插件的更多相关文章

  1. 用Jquery 仿VS 样式的 导航栏插件

    在开发B/S 项目过程中,根据主界面设计要求,需要做一个类似VS 左边工具栏样式的菜单导航栏,在网上搜索无果后,于是决定自已做一个. 由于前台用JQuery开发, 想到网上很多人用JQuery做插件, ...

  2. jQuery自定义Web页面鼠标右键菜单

    jQuery自定义Web页面鼠标右键菜单 右键菜单是固定的,很多时候,我们需要自定义web页面自定义菜单,指定相应的功能. 自定义的原理是:jQuery封装了鼠标右键的点击事件(“contextmen ...

  3. 小程序配置单个页面导航栏的属性(微信小程序交流群:604788754)

    配置单个页面导航栏的属性: 就在所要配置页面相对应的json文件中写入以下想要设置的属性: { "navigationBarBackgroundColor": "#fff ...

  4. JQuery攻略(六)菜单导航

    jQuery菜单导航的基础应用 此章节有 1.0 页面导航 1.01面包屑菜单 1.02菜单悬停 1.03菜单快捷键 1.04两个单独的菜单 1.05折叠菜单 1.01面包屑菜单 html <b ...

  5. ShareSDK(iOS版)开发实践:自定义授权视图和分享视图导航栏

    最近很多人问ShareSDK的授权视图和分享视图的导航栏样式与应用风格不一致,能否修改导航栏的样式?那么这里我就2.6.1版本进行说明(还在使用1.x版本的朋友建议升级到2.x版本,在新版本中可定制的 ...

  6. JQuery实现仿腾讯的固定导航栏

    1.描述 窗口滚动一定高度之后才让导航栏固定 2.要点 浏览器滚动的事件:$(window).scroll(functiuon(){ 文档滚过的高度: $(doucment).scrollTop(); ...

  7. JS+Jquery自定义格式导出HTML为Word(下列插件同样可以用于Excel导出)

    这里的word导出主要采用了jquery.wordexport.js.FileSaver.js,做功能之前我也是找了很多网上的资料,里面涉及到js导出word的用的都是这个插件,只是在自定义样式这一块 ...

  8. jQuery 效果 - slideDown() 方法[菜单导航栏常用]

    实例 以滑动方式显示隐藏的 <p> 元素: $(".btn2").click(function(){ $("p").slideDown(); }); ...

  9. 【原创】js实现一个可随意拖拽排序的菜单导航栏

    1.想做这个效果的原因主要是用在UC上看新闻发现他们的导航菜单很有趣.无聊的时候在哪划着玩了很久.所以就干脆自己写一个.原效果如下 2.整体效果如下,在已推荐和未添加里面每个小方块可以触摸移动位置互换 ...

随机推荐

  1. 三元组ADT (数据结构C语言版) C++实现

    很久没用C语言,都忘了C语言中没有引用参数,下面的代码中用到了C语言没有的引用参数. 首先是一些表示状态的全局变量 common.h #define TRUE 1 #define FALSE 0 #d ...

  2. HDU 6194 后缀数组

    string string string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  3. cxf开发webservice服务器+客户端(各种类型的参数传递返回)

    开发环境:eclipse3.7+jdk1.6.0_29+tomcat6.0.37 XFire搭建webservice: http://www.cnblogs.com/gavinYang/p/35253 ...

  4. 数据分析与展示---Numpy入门

    概括: 一:数据维度 (一)一维数据 (二)二维数据 (三)多维数据 (四)高维数据 二:Numpy的数组对象:ndarray (一)Numpy介绍 (二)N维数组对象ndarray (三)ndarr ...

  5. Intellj IDEA使用技巧记录

    ▲.Intellj IDEA光标变成了insert光标状态 且不能编辑操作: https://blog.csdn.net/aosica321/article/details/52787418 ▲.在i ...

  6. HNOI2004 宠物收养所 (Treap)

    1285 宠物收养所 http://codevs.cn/problem/1285/  时间限制: 1 s  空间限制: 128000 KB     题目描述 Description 最近,阿Q开了一间 ...

  7. Fast File System

    不扯淡了,直接来写吧,一天一共要写三篇博客,还有两篇呢. 1. 这篇博客讲什么? Fast File System(FFS)快速文件系统,基本思想已经在在上一篇博客File System Implem ...

  8. 【BZOJ】1066: [SCOI2007]蜥蜴

    [算法]网络流-最大流(dinic) [题解] 构图思路: 因为石柱高度是可以被消耗的,即一根石柱可通过的蜥蜴数量有限,取舍问题中这样表示容量的属性显然可以作为网络流中的边. 于是将一根石柱拆成顶部和 ...

  9. 【LibreOJ】#6299. 「CodePlus 2018 3 月赛」白金元首与克劳德斯

    [题意]给出坐标系中n个矩形,类型1的矩形每单位时间向x轴正方向移动1个单位,类型2的矩形向y轴正方向,初始矩形不重叠,一个点被矩形覆盖当且仅当它在矩形内部(不含边界),求$(-\infty ,+\i ...

  10. 【BZOJ】2099: [Usaco2010 Dec]Letter 恐吓信

    [题意]给定长度为n和m的两个字符串S和T,要求在字符串S中取出若干段拼成T(可重复取),求最小段数,n,m<=50000. [算法]后缀自动机 || 后缀数组 [题解]对串S建SAM,然后在上 ...