前面的话
首先声明,这个JQuery插件不是我写的,我只是将代码改了一部分而已,在此感谢原作者。
其次替作者推广一下他的作品,这是一个类ExtJS的Tab标签页插件,虽然不是什么高深的东西,但个人使用中感觉还是不错的。
作者的原帖请看这里:
http://www.iteye.com/topic/421360
看到回复中有人质疑作者为什么要重复制造轮子,而且这轮子还不如别人造的圆;而我觉得虽然ExtJS或者其它JQuery插件已经实现了这种东西,而且有很多,但作者自己再写一个为什么不可以呢?作者自己从中学到了东西满足自己成就感的同时,又为大家提供了又一个选择,这不是挺好的事儿吗?
插件怎么用这里不说,有需要的请到作者的原帖中找寻,这里只说一下自己添加右键菜单的修改点。
修改后的插件代码请到这里下载:http://download.csdn.net/detail/zhangyihui1986/5187048
修改原因
原来的TabPanel(即JQuery Tab页面插件)的标签没有右键菜单,其实是浏览器默认的,感觉怪怪地,因为像ExtJS及其它成套的JQuery UI组件中的Tab页面组件都有右键菜单,菜单项包括“关闭/关闭所有/关闭其它/刷新”等功能,于是就想能不能自己扩展一下,也将右键菜单加上以提高用户体验。
花了多半天功夫(水平太次)研究了一下源码,觉得不是很难,于是就将菜单加上了,如下所示:
菜单的样式模仿LigerUI的样子,这里也感谢一下LigerUI的作者。LigerUI其实也算是挺好的一个JQuery UI组件,组件齐全,但Bug挺多,而且文档不全,作者很久没有更新,用过两次之后不敢再用了。
修改点
菜单的UI完全通过JS代码生成,并动态添加去除CSS样式来实现的。
1、CSS修改
首先在原来的TabPanel.css中添加如下样式(样式主要来自LigerUI)
.l-menu {
border: 1px solid #979797;
background: #F5F5F5;
position: absolute;
overflow: hidden;
padding-bottom: 2px;
z-index: 1001;
}
.l-menu-yline {
background: url('../image/TabPanel/menu-line-y.gif') repeat-y;
width: 2px;
height: 2000px;
position: absolute;
left: 28px;
top: 1px;
z-index: 101;
}
.l-menu-over {
position: absolute;
top: -24px;
left: 2px;
z-index: 102;
height: 22px;
overflow: hidden;
background: url('../image/TabPanel/menu-item-over-m.gif') repeat-x;
width: 97%;
}
.l-menu-over-l {
background: url('../image/TabPanel/menu-item-over-l.gif') no-repeat;
width: 28px;
height: 22px;
position: absolute;
top: 0;
left: 0;
}
.l-menu-over-r {
background: url('../image/TabPanel/menu-item-over-r.gif') no-repeat;
width: 3px;
height: 22px;
position: absolute;
top: 0;
right: 0;
}
.l-menu-inner {
position: relative;
width: 100%;
z-index: 103;
}
.l-menu-item {
position: relative;
height: 23px;
line-height: 23px;
width: 100%;
cursor: pointer;
}
.l-menu-item-text {
color: #000000;
left: 33px;
position: absolute;
top: 0;
}
.l-menu-item-icon {
left: 3px;
top: 0;
position: absolute;
width: 25px;
height: 22px;
overflow: hidden;
}
.l-icon-reload {
background: url('../image/TabPanel/refresh.png') no-repeat center;
}
.l-icon-close {
background: url('../image/TabPanel/close.png') no-repeat center;
}
.l-menu-item-disable {
cursor: default;
}
.l-menu-item-disable .l-menu-item-text {
color: #A1A1A1;
}
2、修改TabPanel.js
然后就是修改插件源代码。
2.1、初始化调用
首先在TabPanel初始化方法中调用自己写的CreateMenu方法将弹出菜单创建出来;然后给document对象绑定鼠标单击事件,在事件的响应函数中,将弹出菜单隐藏起来,也就是说如果之前菜单是显示的,当我们在当前页面上点击鼠标左键时弹出菜单隐藏。
this.menu = this.createMenu();
$(document).bind('click', function() {
if (!tabEntity.menu)
return;
tabEntity.menu.hide();
});
2.2、创建菜单
然后定义弹出菜单的生成方法createMenu。
首先创建菜单项承载层DIV,然后循环添加四个菜单项并绑定相应的响应函数,在菜单项配置中可以看到,当鼠标单击某菜单项时会调用_menuItemClick方法并将菜单项配置作为参数传入。最后将弹出菜单追加到body中,由于承载层被定义CSS代码:display:none,所以一开始菜单并不显示。
createMenu : function() {
var tabEntity = this,
menu = $('<div class="l-menu" style="display:none"><div class="l-menu-yline"></div><div class="l-menu-over"><div class="l-menu-over-l"></div><div class="l-menu-over-r"></div></div><div class="l-menu-inner"></div></div>');
menu.items = $("> .l-menu-inner:first", menu);
var allitems = [ {
text : '关闭',
id : 'close',
icon: 'close',
click : function() {
tabEntity._menuItemClick.apply(tabEntity, arguments);
}
}, {
text : '关闭其它',
id : 'closeother',
click : function() {
tabEntity._menuItemClick.apply(tabEntity, arguments);
}
}, {
text : '关闭所有',
id : 'closeall',
click : function() {
tabEntity._menuItemClick.apply(tabEntity, arguments);
}
}, {
text : '刷新',
id : 'reload',
icon: 'reload',
click : function() {
tabEntity._menuItemClick.apply(tabEntity, arguments);
}
} ];
for (var i = 0; i < allitems.length; i++) {
var item = allitems[i],
ditem = $('<div class="l-menu-item"><div class="l-menu-item-text"></div></div>');
ditem.attr("menuitemid", item.id);
$(">.l-menu-item-text:first", ditem).html(item.text);
item.icon && ditem.prepend('<div class="l-menu-item-icon l-icon-' + item.icon + '"></div>');
ditem.click(function(i) {
return function() {
if ($(this).hasClass("l-menu-item-disable"))
return;
item.click(i);
}
}(item));
var menuover = $("> .l-menu-over:first", menu);
ditem.hover(function() {
if ($(this).hasClass("l-menu-item-disable"))
return;
var itemtop = $(this).offset().top;
var top = itemtop - menu.offset().top;
menuover.css({
top : top
});
}, null);
menu.items.append(ditem);
}
menu.hover(null, function() {
$("> .l-menu-over:first", menu).css({
top : -24
});
});
return menu.css({
width : '100px'
}).appendTo('body');
}
2.3、显示菜单
第三步就是绑定右键事件响应函数,这部分代码添加Tab标签页的方法中(addTab方法),而右键事件被绑定在tab上,也就是一个li元素,左键点击该Tab标签用以切换页面显示,右键点击弹出菜单。
// 绑定右键事件
tab.bind('contextmenu', function(e) {
if (tabEntity.menu) {
tabEntity.actionTabId = tabitem.id;
tabEntity.menu.css({
top : e.pageY,
left : e.pageX
}).show();
if (!tabEntity.tabs[tabEntity.getTabPosision(tabEntity.actionTabId)].closable) {
$("> .l-menu-item[menuitemid='close']", tabEntity.menu.items).addClass("l-menu-item-disable");
} else {
var closeItem = $("> .l-menu-item[menuitemid='close']", tabEntity.menu.items);
if (closeItem.hasClass("l-menu-item-disable"))
closeItem.removeClass("l-menu-item-disable");
}
}
return false;
});
由上面代码可以看出,其实就是将菜单显示在鼠标点击的位置,然后阻止系统默认的右键菜单出现。如果右键事件发生的Tab标签不可关闭,即在添加该标签页时将closable设置为false,那么将“关闭”菜单项设置为禁用状态,反之设置为启用状态。
2.4、菜单项回调
最后就是定义当用户点击弹出菜单的菜单项时的响应函数了,仅仅是根据菜单的不同执行相应的逻辑(或关闭标签或刷新页面)。
代码如下所示:
// 菜单项点击
_menuItemClick: function (menuitem) {
var tabEntity = this;
switch (menuitem.id) {
case 'close':
this.kill(this.actionTabId);
this.actionTabId = null;
break;
case 'closeother':
$(this.tabs).each(function () {
if (tabEntity.actionTabId != this.id) {
tabEntity.kill(this.id);
}
});
break;
case 'closeall':
$(this.tabs).each(function () {
tabEntity.kill(this.id);
});
break;
case 'reload':
this.flush(this.actionTabId);
break;
default:
break;
}
}
至此,整个修改完成,其实也很简单。