本人-----咳咳,只是一只后端菜鸟不是什么大侠,本来准备好的牛哄哄的武侠开场白就这么垮掉了。。。
进入正题:
最近再做一棵后台菜单管理的菜单树,遍访互联网上各大树表格插件,结果让人无奈,不是功能不满足就是封装的太死,样式丑的让人难以接受(对于现在这个年代来说),一番对比最终选择了詹潮江大神的JqueryTreeTable插件。
然而可能世界上并不存在完美吧,使用过程中需要进行增删改查,然后大家懂得,操作完以后自然是要刷新页面的,像
self.location.reload();
这种没含量的刷新就不说了,树本身采用ajax请求数据来构造,而且整个系统都是采用ajax加载数据局部刷新,而只有这个页面刷新了,用户体验并不好,所以理所当然的认为是通过重新调用一下初始化方法就解决的事儿。
初始化方法:
function initTreeTable() {
var tpl = $("#tableTpl").html().replace(/(\/\/\<!\-\-)|(\/\/\-\->)/g, "");
$.ajax({
type: "get",
url: baseURL + "/bg/menu/menu_data", // 请求地址
dataType: "json",
success: function (data) {
var con = data.rows;// 获取json中的list列表
for (var i = 0; i < con.length; i++) {
// 采用Mustache来设置模板内容
$("#menuTreeTable").append(Mustache.render(tpl, {
row: con[i],
pid: con[i].parent.menuId != '1' ? con[i].parent.menuId : '0'
}));
}
$("#menuTreeTable").append(showContent);
// 以下为初始化表格样式
var option = {
theme: 'default',
expandLevel: 2
};
$('#menuTreeTable').treeTable(option);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
showMsg(2, "", "");
}
});
}
然而凉凉了。。。
我的树确实再次刷新出来了,可是我险些将屏幕点碎了,我的子菜单也没显示出来
于是开始了读詹大哥源码的过程。。。最终发现了问题所在。这个菜单前面的小三角其实是一个span,詹大哥为它绑定了点击事件。。此部分源码如下
$treeTable.click(function (event) {
var $target = $(event.target);
if ($target.attr('controller')) {
$target = $target.parents('tr[haschild]').find('[arrow]');
//判断是否是叶子节点
if ($target.attr('class').indexOf(css['AN']) == -1 && $target.attr('class').indexOf(css['N']) == -1) {
return;
}
var id = $target.parents('tr[haschild]')[0].id;
if (opts.onSelect && opts.onSelect($treeTable, id) === false) {
return;
}
}
if ($target.attr('arrow')) {
var className = $target.attr('class');
if (className == css['AN'] + ' ' + css['HLO'] || className == css['AN'] + ' ' + css['HO']) {
var id = $target.parents('tr[haschild]')[0].id;
$target.attr('class', css['AN'] + " " + (className.indexOf(css['HO']) != -1 ? css['HS'] : css['HLS']));
//关闭所有孩子的tr
shut(id);
return;
} else if (className == css['AN'] + ' ' + css['HLS'] || className == css['AN'] + ' ' + css['HS']) {
var id = $target.parents('tr')[0].id;
$target.attr('class', css['AN'] + " " + (className.indexOf(css['HS']) != -1 ? css['HO'] : css['HLO']));
opts.beforeExpand($treeTable, id);
//展开所有直属节点,根据图标展开子孙节点
open(id);
return;
}
}
});
思路其实很简单了,通过判断当前按钮的样式来执行不同的操作,至于按钮样式是怎么变化的,源码如下:
$treeTable.mouseover(hoverActiveNode).mouseout(hoverActiveNode);
function hoverActiveNode(event) {
var $target = $(event.target);
if ($target.attr('controller')) {
$target = $target.parents('tr[haschild]').find('[arrow]');
}
if ($target.attr('arrow')) {
var className = $target.attr('class');
if (className && !className.indexOf(css['AN'])) {
var len = opts.theme.length + 1;
className = className.split(' ')[1].substr(len);
if (className.indexOf('hover_') === 0) {
className = opts.theme + '_' + className.substr(6);
} else {
className = opts.theme + '_hover_' + className;
}
$target.attr('class', css['AN'] + ' ' + className);
return;
}
}
}
詹大哥为这个span三角按钮绑定了mouseover和mouseout事件,当鼠标移入时,添加hover样式。
思路大概讲完了,源码并不复杂,那么问题到底出在什么地方?为什么第一次进入页面初始化树表格点击父节点可以展开子节点呢?而第二次就失效了?
答案就在为span绑定点击事件click上!!
第一次进入页面初始化树表格为span绑定了一个点击事件,点击后展开树节点。
当手动刷新表格,再次调用初始化方法初始化树表格后再次为span绑定了一个点击事件,这时,由于页面没有刷新,第一次绑定的点击事件还在!! 所以结果就是点击span后确实展开了子节点,然后在你还没有意识到,第二个点击事件就把刚刚展开的子节点又合上了。。。所以看起来点击后根本没反应。。
所以答案显而易见了,只需要在每一次绑定前先解绑再绑定就可以了,修改后的源码如下:
$treeTable.off('click').on('click',function (event) {
// $treeTable.click(function (event) {
由于篇幅太长,只提供修改部分的代码。修改后就可以发现,好用了!!
题外话:span的鼠标事件和点击事件还是有些效率低下的,因为是对table对象绑定的事件,所以一个那么大的table,不管你点哪还是鼠标移到哪都会触发事件进行判断。。。
所以个人认为直接将鼠标事件和点击事件绑在span上就好了。。。
点击事件
$treeTable.find('span').off('click').on('click',function (event) {
移入移出事件
$treeTable.find('span').mouseover(hoverActiveNode).mouseout(hoverActiveNode);
大功告成!!!