用jQuery做表格控件
时间:2011-04-11 来源:元某人
网上类似的jQuery和非jQuery表格控件都非常多了,由于项目需要,我没有时间去找一个合适且小巧的表格控件,于是自己写了一个。这个表格控件要实现如下的目标:
1.列宽可以控制
2.有鼠标滑过和选中高亮效果
3.标题列支持添加排序回调函数
4.事件绑定要少,因为表格数据是ajax动态加载的
5.支持多选
首先用HTML写一个表格框架,这里表扬一下特别好用的Zen Coding插件,写table.colortable>thead>tr>th*4就可以生成所需的结构
<table class="colortable">
<thead>
<tr>
<th>列A</th>
<th>列B</th>
<th>列C</th>
<th>列D</th>
</tr>
</thead>
</table>
表格内容是动态生成的,因此只需要一个tbody标签即可,但为了调试方便,先给两行数据。
<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前缀。
.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按下时是增加选择模式,不按则是单选模式。
处理排序时,对应每列的三种状态(默认,正序,逆序)要写三种不同的处理方式。
完整代码如下:
(function($){
$.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里也未尝不可。