世俱杯 2025

JavaScript Table行定位效果(一)

原创|其它|编辑:郝浩|2009-05-20 10:13:09.000|阅读 829 次

概述:近来有客户要求用table显示一大串数据,由于滚动后就看不到表头,很不方便,所以想到这个效果。 上次做table排序对table有了一些了解,这次更是深入了解了一番,发现table原来是这么不简单。

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>

近来有客户要求用table显示一大串数据,由于滚动后就看不到表头,很不方便,所以想到这个效果。
上次做对table有了一些了解,这次更是深入了解了一番,发现table原来是这么不简单。
还不清楚这个效果叫什么,有点像表头固定的效果,就叫行定位吧,本来想把列定位也做出来,但暂时还没这个需求,等以后有时间再弄吧。
如果只是做一个效果也不难,但要做一个通用的,无侵入的就要考虑很多东西了。


效果预览

为方便预览,建议缩小浏览器。

1 表头  
1 表头  
2  
3  
4
5  
6  
7  
8
9  
10  
11  
12
13  
14  
15  
16
17 表尾  


点击行选择克隆行:当前克隆第 1

 


程序原理

一开始的需求只是表头部分在滚动时能一直固定在头部,那关键要实现的就是让tr能定位。
首先想到的方法是给tr设置relative,用ie6/7测试以下代码:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="//www.w3.org/1999/xhtml">
<body>
<table cellpadding="5" cellspacing="0" border="1" width="100">
    
<tr style="position:relative; left:100px;">
         
<td>1</td>
         
<td>2</td>
    
</tr>
    
<tr>
         
<td>3</td>
         
<td>4</td>
    
</tr>
</table>
</body>
</html>


给tr设置relative后就能相对table定位了,看来很简单啊,但问题是这个方法ie8和ff都无效,而且存在很多问题,所以很快就被抛弃了。
ps:该效果用来做tr的拖动会很方便。

接着想到的是给table插入一个新tr,克隆原来的tr,并设置这个tr为fixed(ie6为absolute),例如:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="//www.w3.org/1999/xhtml">
<body>
<table cellpadding="5" cellspacing="0" border="1" width="100">
    
<tr style="position:fixed; left:100px;">
         
<td>1</td>
         
<td>2</td>
    
</tr>
    
<tr style="position:absolute; left:200px;">
         
<td>3</td>
         
<td>4</td>
    
</tr>
    
<tr>
         
<td>5</td>
         
<td>6</td>
    
</tr>
</table>
</body>
</html>


第一个问题是fixed的tr在ie7中不能进行定位,而且td在定位后并不能保持在表格中的布局,这样在原表格插tr就没意义了。
ps:fixed的相关应用可参考。

最后我用的方法是新建一个table,并把源tr克隆到新table中,然后通过对新table定位来实现效果。
 用这个方法关键有两点,首先要做一个仿真度尽可能高的tr,还有是要准确的定位,这些请看后面的程序说明。


程序说明

【克隆table】

克隆一个元素用cloneNode就可以了,它有一个bool参数,表示克隆是否包含子节点。
程序第一步就是克隆原table:

this._oTable = $(table);//源table
this._nTable = this._oTable.cloneNode(false);//新table
this._nTable.id = "";//避免id冲突


要注意虽然ie的cloneNode参数是可选的(默认是false),但在ff是必须的,建议使用时都写上参数。
还要注意的是id属性也会被克隆,也就是克隆后会有两个相同id的元素(如果克隆对象有设置的话),这很容易会导致其他问题,程序会把克隆table的id属性设空。
ps:table请用class来绑定样式,用id的话新table就获取不了样式了。

克隆之后再设置样式:

this._style.width = this._oTable.offsetWidth + "px";
this._style.position = isIE6 ? "absolute" : "fixed";
this._style.zIndex = 100;


 一般来说offsetWidth是width+padding+border的结果,但table比较特别,测试下面的代码:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="//www.w3.org/1999/xhtml">
<body>
<table border="5" id="t" style="padding:10px; width:100px;">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
<table width="100" id="t2" style="border:10px solid #000;">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
<script>
alert(document.getElementById(
"t").offsetWidth);
alert(document.getElementById(
"t2").offsetWidth);
</script>
</body>
</html>


只要给table设置width(style或本身的width属性),不管设置padding和border是多少,offsetWidth都等于width的值。
经测量offsetWidth是没错的,那就是说是table的width设置的问题。
中说width属性是the desired width of the entire table,我估计entire就是包含了padding和border,找不到什么其他说明,先这么理解吧。
定位方面,除了不支持fixed的ie6用absolute,其他都使用fixed定位。


【克隆tr】

table有一个rows集合,包括了table的所有tr(包括thead和tfoot里面的)。
程序的Clone方法会根据其参数克隆对应索引的tr:

this._index = Math.max(0, Math.min(this._oTable.rows.length - 1, isNaN(index) ? this._index : index));
this._oRow = this._oTable.rows[this._index];
var oT = this._oRow, nT = oT.cloneNode(true);


由于tr可能是包含在thead这些中,所以还要判断一下:

if(oT.parentNode != this._oTable){
    nT 
= oT.parentNode.cloneNode(false).appendChild(nT).parentNode;
}


然后再插入到新table中:

if(this._nTable.firstChild){
    
this._nTable.replaceChild(nT, this._nTable.firstChild);
}
else{
    
this._nTable.appendChild(nT);
}


 因为程序允许修改克隆的tr,所以会判断有没有插入过,没有就直接appendChild,否则用replaceChild替换原来的tr。

 
【table的border和frame属性】

table的border属性用来指定边框宽度,table特有的frame属性是用来设置或获取表格周围的边框显示的方式。
说明frame可以是以下值:
void: No sides. This is the default value.
above: The top side only.
below: The bottom side only.
hsides: The top and bottom sides only.
vsides: The right and left sides only.
lhs: The left-hand side only.
rhs: The right-hand side only.
box: All four sides.
border: All four sides.
这些值指明了要显示的边框。要留意的是虽然说void是默认值,但不设置的话其实是一个空值,这时四条边框都会显示。
还有frame对style设置的border没有效果,测试下面代码:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="//www.w3.org/1999/xhtml">
<body>
<table width="100" border="5" frame="lhs">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
<table width="100" style="border:5px solid #000;" border="10" frame="lhs">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
</body>
</html>


 这里还可以看到如果同时设置table的border和style的border,那table的border就会失效。

程序中为了更美观会自动去掉新table上面和下面的边框,包括frame和style的:


if(this._oTable.border > 0){
    
switch (this._oTable.frame) {
         
case "above" :
         
case "below" :
         
case "hsides" :
             
this._nTable.frame = "void"break;
         
case "" :
         
case "border" :
         
case "box" :
             
this._nTable.frame = "vsides"break;
    }
}
this._style.borderTopWidth = this._style.borderBottomWidth = 0;


其中空值在设置collapse之后会比较麻烦,在ie6/ie7中测试:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="//www.w3.org/1999/xhtml">
<body>
<style type="text/css">
.t
{width:100px; border-collapse:collapse;}
.t td
{border:5px solid #999;}
</style>
<table class="t">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
<br />
<table class="t" frame="vsides">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
<br />
<table class="t" border="1">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
<br />
<table class="t" border="1" frame="vsides">
    
<tr>
         
<td>1</td>
         
<td>1</td>
    
</tr>
</table>
</body>
</html>


后两个的转换还可以接受,所以在设置frame之前还是判断一下border先。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@dpuzeg.cn

文章转载自:博客园

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP