网上类似的jQuery和非jQuery表格控件都非常多了,由于项目需要,我没有时间去找一个合适且小巧的表格控件,于是自己写了一个。这个表格控件要实现如下的目标:
1.列宽可以控制
2.有鼠标滑过和选中高亮效果
3.标题列支持添加排序回调函数
4.事件绑定要少,因为表格数据是ajax动态加载的
5.支持多选
首先用HTML写一个表格框架,这里表扬一下特别好用的Zen Coding插件,写table.colortable>thead>tr>th*4就可以生成所需的结构
< thead >
< tr >
< th > 列A </ th >
< th > 列B </ th >
< th > 列C </ th >
< th > 列D </ th >
</ tr >
</ thead >
</ table >
表格内容是动态生成的,因此只需要一个tbody标签即可,但为了调试方便,先给两行数据。
< tr >
< td > 1 </ td >
< td > 2 </ td >
< td > 3 </ td >
< td > 4 </ td >
</ tr >
< tr >
< td > 5 </ td >
< td > 6 </ td >
< td > 7 </ td >
< td > 8 </ td >
</ tr >
</ tbody >
接下来应用一些CSS让表格显得美观,由于要做成控件,因此CSS里也特意给每个选择器加了.colortable前缀。
border-collapse : collapse ;
display : inline-block ;
cursor : pointer ;
}
.colortable tr {
text-align : center ;
height : 22px ;
line-height : 22px ;
}
.colortable td,th { border : 1px solid #000 ; overflow : hidden ; }
.colortable th.orderA,th.orderD {
background : url("../pic/common/table_order.gif") repeat-x ;
color : white ;
}
.colortable tbody { background-color : #BBE0FF ; }
.colortable thead { background : url("../pic/common/table.gif") repeat-x ; }
.colortable tr.high { background-color : #E4F4FC ; }
.colortable tr.sel,td.order { background-color : #39B2E4 ; color : white ; }
这里用了两张图片:table_order.gif是在列排序时突出显示列标题用的,table.gif是标题的默认效果,我用了一点浅渐变来美化。
接下来就是js部分,考虑到要动态设置表格的列宽,因此要传入各个列宽的数组。再为排序传入两个回调函数。
代码的实现部分没有太多难度,主要就是在处理鼠标滑过效果时要区分该行是否被选中,选中行已经高亮了,就不需要滑过效果。
处理多选时也需要考虑两种情况,ctrl按下时是增加选择模式,不按则是单选模式。
处理排序时,对应每列的三种状态(默认,正序,逆序)要写三种不同的处理方式。
完整代码如下:
$.fn.initTable = function (width,orderA,orderD){
var that = this ;
that.children( " thead " ).click( function (event){
var target = event.target;
var index = $(target).index();
// 干掉高亮行
var sel = getByClass( " sel " , " tr " );
for ( var i = 0 ,len = sel.length;i < len;i ++ )
sel[i].className = "" ;
if (target.className == "" ){ // 升序
// 干掉其他th.order
var thd = getByClass( " order " , " td " );
for ( var i = 0 ,len = thd.length;i < len;i ++ )
thd[i].className = "" ;
thd = getByClass( " orderA " , " th " );
if (thd.length > 0 )
thd[ 0 ].className = "" ;
thd = getByClass( " orderD " , " th " );
if (thd.length > 0 )
thd[ 0 ].className = "" ;
// 加类
target.className = " orderA " ;
that.find( " tbody tr " ).each( function (){
$( this ).children( " td " ).eq(index).attr( " class " , " order " );
});
orderA(index);
} else if (target.className == " orderD " ){ // 取消排序
target.className = "" ;
var td = getByClass( " order " , " td " );
for ( var i = 0 ,len = td.length;i < len;i ++ )
td[i].className = "" ;
} else { // 降序
target.className = " orderD " ;
orderD(index);
}
}).find( " th " ).each( function (i){
this .style.width = width[i] + " px " ;
}).end().end().children( " tbody " ).click( function (event){
var target = event.target.parentNode;
if (event.ctrlKey) // 多选
target.className = (target.className == " sel " ) ? "" : " sel " ;
else {
if (target.className == " sel " ){
var sel = getByClass( " sel " , " tr " );
for ( var i = 0 ,len = sel.length;i < len;i ++ )
sel[i].className = "" ;
} else {
var sel = getByClass( " sel " , " tr " );
for ( var i = 0 ,len = sel.length;i < len;i ++ )
sel[i].className = "" ;
target.className = " sel " ;
}
}
}).mouseover( function (event){
var target = event.target.parentNode;
if (target.className != " sel " )
target.className = " high " ;
}).mouseout( function (event){
var target = event.target.parentNode;
if (target.className != " sel " )
target.className = "" ;
});
};
})(jQuery);
代码里的getByClass是我写的按class查找元素的函数。运行效果如图:
选中一行的效果
排序效果
最后,设置表格内容不能直接设置tbody的innerHTML,因为IE不支持。replaceChild也不行,IE不支持。
直接createElement/appendChild方法可以。
用jQuery的.html()方法可以。
通过动态插入3000行比较性能,FF,OP,SAR,CHR两种方法都控制在100ms内。生成后,动态效果都很流畅。
IE6用第一种方法500ms,第二种方法1680ms。但是动态效果几乎瘫痪,反应极慢。诡异的是,目测下来,IE6对点击的反应要略快于滑过效果。但是我的滑过效果代码只有3行,没有任何查找和遍历,只改了一个class,而点击效果里还有一个全行遍历。我怀疑影响性能的是那个class切换导致css全部重新计算。因此我将滑过效果中的class切换去掉,改为直接赋值背景色,于是问题解决了,IE6中滑动流畅。
但是这影响了控件的独立性,我尝试恢复class切换,同时注释掉css里的规则,在js中改颜色。性能问题又重现了。可见性能瓶颈不是css计算,而在于class赋值本身。改用setAttribute赋值也无济于事。
好吧,一般的表格不会有3000行之巨,经测试,行数在500行之内,IE6的性能问题不明显,但快速滑动还是能看出高亮显示滞后,此时IE6生成表格的时间刚好降到100ms以内。行数继续降到100行,IE6才能达到Firefox的流畅度。这可能是因为我的Firefox是4.0的。
无论如何,让表格行数限制到100行,还是有点不人道。我也暂时想不到更好的解决办法,如果不考虑控件通用性,把颜色写到js里也未尝不可。