JavaScript Table行定位效果

近来有客户要求用table显示一大串数据,由于滚动后就看不到表头,很不方便,所以想到这个效果。
上次做table排序对table有了一些了解,这次更是深入了解了一番,发现table原来是这么不简单。
还不清楚这个效果叫什么,有点像表头固定的效果,就叫行定位吧,本来想把列定位也做出来,但暂时还没这个需求,等以后有时间再弄吧。
淘宝的商品搜索页也看到类似的效果,但淘宝的不是table,而是li,而我这个是用在table上的。
要说明一下的是,我这个效果是用在一些普通的产品列表,当数据比较多时提高用户体验,而不是单单做数据显示,跟excel那样的方式是不同的。


效果预览

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

表头
图片滑动切换效果
图片变换效果(ie only)
图片切割效果
仿LightBox内容显示效果
图片滑动展示效果
仿163网盘无刷新文件上传系统
拖放效果
图片切割系统
自定义多级联动浮动菜单
滑动条效果
拖拉缩放效果
渐变效果
Table排序
Tween算法及缓动效果
颜色梯度和渐变效果
表尾

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



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

注意,使用ie8的兼容性视图会有偏移。


程序原理

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

Code


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

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

Code


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

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


程序说明

【克隆table】

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

this._oTable = $$(table);
this._nTable = this._oTable.cloneNode(false);
this._nTable.id = "";


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

克隆之后再设置样式:

$$D.setStyle(this._nTable, {
    width: 
this._oTable.offsetWidth + "px",
    position: $$B.ie6 
? "absolute" : "fixed",
    zIndex: 
99, borderTopWidth: 0, borderBottomWidth: 0
});


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

Code


只要给table设置width(style或本身的width属性),不管设置padding和border是多少,offsetWidth都等于width的值。
经测量offsetWidth是没错的,那就是说是table的width设置的问题。
w3c的table部分中说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属性是用来设置或获取表格周围的边框显示的方式。
w3c的tabel的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没有效果,测试下面代码:

Code


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

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

Code


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

Code


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


【获取背景色】

如果td是背景透明的话显然不太美观,最好是找一个合适的颜色来填充。
程序用的方法是,从当前td开始找,如果背景是透明的话,就再从父节点中找,直到找到有背景色为止。
一般来说透明的属性值是"transparent",但在chrome和safari里却是"rgba(0, 0, 0, 0)",所以用了一个属性来保存透明值:

_transparent: $$B.chrome || $$B.safari ? "rgba(0, 0, 0, 0)" : "transparent",


并在_getBgColor获取背景色程序中使用:

var bgc = "";
while (bgc === this._transparent && (node = node.parentNode) != document) {
    bgc 
= $$D.getStyle(node, "backgroundColor");
}
return bgc === this._transparent ? "#fff" : bgc;


如果全部都是透明的话就会返回白色(#fff)。
这里没有考虑图片背景的情况,毕竟图片不一定会覆盖整个背景。


【parentNode/offsetParent/parentElement】

上面用到了parentNode,这里顺便说说它跟offsetParent,parentElement的区别。
先看看parentNode在w3c的说明:
The parent of this node. All nodes, except Document, DocumentFragment, and Attr may have a parent. However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is null.
很简单,就是节点的父节点,看过dom都知道。

再看看比较容易区分的offsetParent,它在mozilla和msdn都说得比较模糊,在w3c就比较清楚了:
The offsetParent attribute, when called on element A, must return the element determined by the following algorithm:
1,If any of the following holds true return null and stop this algorithm:
A is the root element.
A is the HTML body element.
The computed value of the position property for element A is fixed.
2,If A is an area HTML element which has a map HTML element somewhere in the ancestor chain return the nearest ancestor map HTML element and stop this algorithm.
3,Return the nearest ancestor element of A for which at least one of the following is true and stop this algorithm if such an ancestor is found:
The computed value of the position property is not static.
It is the HTML body element.
The computed value of the position property of A is static and the ancestor is one of the following HTML elements: td, th, or table.
4,Return null.
这里主要有四点:
1,如果是根元素、body元素或元素的position是fixed,将返回null;
2,如果是area元素,会返回最接近的map元素;
3,返回至少符合以下一个条件的最接近该节点的元素:1,元素的position不是static;2,是body元素;3,源元素的position是static,祖先元素中的以下元素:td,th或table。
4,返回null。
其中第三点是最常见的情况,详细可以看下面的测试:

Code


可见offsetParent跟parentNode的区别还是很大的。

而parentNode跟parentElement除了前者是w3c标准,后者只ie支持,其他的区别就不是那么明显了。
在ie中大部分情况下两者的效果是一样的,当然如果是一模一样的话ie就没必要弄这么一个东西出来了,测试下面的代码:

Code


可以看到当父节点的nodeType不是1,即不是element节点的话,它的parentElement就会是null。
这就明白了名字中“Element”的含义了。


【设置td宽度】

接下来就要设置td宽度了,要获取某元素的宽度可以通过以下方法:
1,支持defaultView的可以直接用getComputedStyle获取width。
2,获取offsetWidth,再减去border和padding的宽度。
这个本来也可以,但td的border宽度的获取比较麻烦,下面有更方便的方法。
3,获取clientWidth,再减去padding的宽度。
这个跟方法2差不多,但更简单方便。

注意ie的currentStyle不像getComputedStyle能获取准确值,而只是一个设置值,像百分比、auto这些并不会自动转成准确值,即使是得到准确值也不一定是实际值,例如td即使设置一个很大的准确值,实际值也不会超过table本身的宽度。
所以在td这种比较特殊的结构中,不要用currentStyle来获取td的宽度。
对于支持defaultView的当然可以直接获取,否则就用上面的方法3来获取:

style.width = (document.defaultView ? parseFloat(getStyle(o, "width"))
    : ( o.clientWidth 
- parseInt(getStyle(o, "paddingLeft")) - parseInt(getStyle(o, "paddingRight")) )) + "px";


但这里不管哪个方法都有一个问题,就是出现scroll的情况,不过还好td这个元素即使设置了overflow为scroll也不会出现滚动条,除了ie8和chrome。
程序没对这个情况做处理,毕竟给td设scroll也不常见,而且支持这个的浏览器不多,没必要花太多时间在这里。
ps:关于td宽度的自动调整可以参考w3c的table-layout部分

如果有影响原td结构的设置,例如colspan之类的就要留意,错误的结构很可能导致一些异常变形。
如果对原表格结构或内容做了修改,应该执行一次clone方法重构新table。
本部分对体验比较重要,如果设置不当就会有变形的感觉,很不美观。


【borderCollapse】

上面说到td的border宽度的获取比较麻烦,那到底有多烦呢?
如果只是一般情况的话,通过borderLeftWidth和borderRightWidth获取宽度就可以了。
ps:如果borderStyle是"none"的话,那么border就会没效,所以如果要取border宽度的话最好先判断一下borderStyle是不是"none"。

但table有一个特别的样式borderCollapse,设置table的边框模型。
它有两个值,分别是separate(分开,默认值)和collapse(合并)。
separate就是我们一般看到的效果,这里主要讨论collapse,先看mozilla怎么说的:
In the collapsed border model, adjacent table cells share borders.
意思是在collapse border模型中,相邻的td会共用边框。看下面的例子会更明白:

Code


可以看到使用collapse之后,相邻td的边框都会变成一条。
再看w3c中Border conflict resolution的部分,可知相邻边框会按以下规则获取优先级最高的边框:
1,'border-style'是'hidden'的优先级最高;
2,'border-style'是'none'的优先级最低;
3,'border-width'大的优先级更高;
4,接着按以下'border-style'由高到低排列:'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', 'inset';
5,接着按以下border所属对象由高到低排列:cell,row,row group,column,column group,table;
6,以上都一样的话,最后按left优先,top优先排列。

ps:从Border styles可知'hidden'和'none'的'border-style'基本是一样的,区别就在于collapse时的优先级。

那td跟table之间呢,参考下面的例子:

Code


可见table和td之间也是遵从同样规则。
还有的是当设置了collapse那cellspacing就无效了。顺便说说border-spacing,它其实就是cellspacing在css中的样式形式,只是ie在ie8才开始支持,详细可以看mozilla的说明

collapse的一个常见应用是做边框表格,例如1px边框的表格:

Code


前者用的collapse,后者是用table背景色模拟,虽然效果都一样,但前者显然较好,才是真正的“边框”。

在使用了collapse之后,要写一个通用的获取边框宽度程序会变得十分麻烦,而且有些情况下甚至没办法判断获取。
详细情况这里就不细说了,有兴趣研究的话可以看看w3c的The collapsing border model,当然要想全部了解的话还要在各个浏览器中研究。


【元素位置】

table的样式设置好后,还需要获取原table和原tr的位置参数,为后面的元素定位做准备。
要获取某个元素相对文档的位置,传统的做法是获取对象的offsetLeft/offsetTop,然后不断获取offsetParent的offsetLeft/offsetTop,直到找不到offsetParent为止。
得到的结果就是相对文档的位置了,上面已经介绍过offsetParent,原理应该都明白了吧。

不过这里介绍一个更好的方法,通过getBoundingClientRect方法来获取。
mozilla是这么说明的:
The returned value is a TextRectangle object, which contains read-only left, top, right and bottom properties describing the border-box, in pixels, with the top-left relative to the top-left of the viewport...
返回一个TextRectangle对象,包含left, top, right和bottom几个只读属性,以px为单位来表示边界框相对视窗左上角的位置。(偶英文烂啊)
注意是相对视窗,不是文档哦,如果要相对文档还必须加上scrollLeft/scrollTop。
通过下面的测试可以看到两个方法返回的结果都是相同的:

Code


程序中就是用getBoundingClientRect来获取位置参数,显然用getBoundingClientRect更方便快捷。
这个方法虽然是ie的产物,但已经是w3c的标准,而且ff3,Opera和最新版的chrome都已经支持了这个方法,可以放心使用。
这里只是简单介绍,想了解更多可以看w3c的View Module部分

获取原table和tr的位置后,还需要计算新table的位置。
程序可以自定义新table位于视窗位置的百分比,例如顶部是0,中间是0.5,底部是1,可以在程序初始化时或用setPos方法来设置。
这里主要获取视窗高度和新table在视窗的top值:

this._viewHeight = document.documentElement.clientHeight;
this._nTableViewTop = (this._viewHeight - this._nTableHeight) * this._pos;


定位范围实际上是从视框顶部到视框高度减去新table高度的范围内的,所以计算时要先把视窗高度减去新table的高度。


【元素定位】

万事俱备,只欠定位了。
由于要根据窗口滚动状态来判断计算定位,scrollTop/scrollLeft的获取必不可少。
但要注意在chrome/safari中就算用了DOCTYPE,也要用document.body来获取scrollTop/scrollLeft,尽管它确实有document.documentElement。
定位的第一步就是判断是否需要定位,这里的判断标准有两个,第一个是原tr是否超过了视窗范围,还有是新table要显示的位置是否在原table的显示范围内。
第一点可以通过原tr位置的顶部和底部是否超过视窗的顶部和底部来判断:

Code


在看第二点之前先看看程序中的auto属性,它是用来指定否自动定位的。
如果自动定位的话当原tr离开视框顶部新table就会定位到视框顶部,原tr离开底部新table就会定位到视框底部,这样看上去会比较自然顺畅。
如果不选择自动的话就会根据setPos方法中计算得到的新table视窗top值来设置定位:

var viewTop = !this.auto ? this._nTableViewTop
        : (outViewTop 
? 0 : (this._viewHeight - this._nTableHeight))
    ,posTop 
= viewTop + top;


接着就判断新table要显示的位置是否在原table的显示范围内,这个可以通过新table位置的顶部和底部是否超过原table的顶部和底部来判断:

if( posTop > this._oTablePos.top && posTop + this._nTableHeight < this._oTablePos.bottom ){  }


当符合所有的条件就可以进行定位了,如果是fixed定位的就使用相对视窗的top值:

tStyle.top = viewTop + "px";
tStyle.left 
= this._oTablePos.left - left + "px";


像ie6是absolute定位的就要使用相对文档的top值:

tStyle.top = posTop + "px";
tStyle.left 
= this._oTablePos.left + "px";


考虑到左右滚动的情况,left也必须设置。

当然不符合条件就会隐藏新table,程序中给top设置一个很大的负值来间接“隐藏”它。
用负值是因为这样不会把ie6的页面拉长,不用display是因为上面需要获取它的offsetHeight,如果用display隐藏就获取不了啦。

最后把run程序绑定到window的scroll事件中就可以了,而window在resize时视框高度会发生变化,所以resize事件要绑定setPos程序。


【覆盖select】

只要用到了定位,就不得不面对一个老对手“ie6的select”。
我在之前的文章也介绍过一些解决方法(参考这里的覆盖select),这里不能直接隐藏select,那看来只能用iframe了。
但用iframe有一个很大的问题,在ie6测试下面的代码,并拖动滚动条:

Code


可以看到,即使是iframe,在拖动滚动条的时候,select仍然在后面闪啊闪,在本程序中这个现象会尤其明显。
看来还得用隐藏select的方法,最好的做法是只隐藏在新table后面的select,而不影响其他select的正常显示。
那关键就是如何判断select是否在新table后面,这个可以通过位置坐标判断。
一般的思路是判断新table和select的坐标,根据位置判断select的显示和隐藏。
但如果有多个实例,可能会导致select在一个实例中要隐藏,却在另一个要显示的情况。

为了解决冲突,程序给select加了一个_count属性作为计数器,用来记录有多少实例把该select隐藏了。
如果当前实例判断该select要隐藏,就给其_count加1,隐藏后存放到实例的_selects集合中。
在恢复显示_selects中的select时,先给select的_count减1,如果得到的_count是0,那说明没有其他实例要隐藏它,就可以设置显示了,最后清空_selects集合。
在判断是否隐藏select前还必须恢复一次该实例_selects里面的select,否则就会造成_count只加不减的情况。

程序中的_setSelect方法就是用来判断和设置select的:

Code


其中_resetSelect方法是用来恢复显示select的:

$$A.forEach( this._selects, function(o){ !--o._count && ( o.style.visibility = o._css ); } );
this._selects = [];


但这个方法在快速滚屏时还是无能为力,而且select越多效率也随之下降,各位有更好方法的话欢迎交流。


使用说明

实例化一个TableFixed对象只需要一个参数table的id:

new TableFixed("idTable");


实例化时有4个可选属性:
index: 0,//tr索引
auto: true,//是否自动定位
pos: 0,//自定义定位位置百分比(0到1)
hide: false//是否隐藏(不显示)

其中index和pos在实例化之后就不能使用。
要修改克隆行可以用clone方法,其参数是要克隆tr的索引。
要修改自定义定位位置可以用setPos方法,其参数是要定位的位置百分比。

具体使用请参考实例。


程序源码

Code

 

下载完成测试代码 

转载请注明出处:http://www.cnblogs.com/cloudgamer/

如有任何建议或疑问,欢迎留言讨论。

如果觉得文章不错的话,欢迎点一下右下角的推荐。

对广告有兴趣的也欢迎点一下^_^。

3
0
(请您对文章做出评价)
« 上一篇:JavaScript 颜色梯度和渐变效果
» 下一篇:JavaScript 浮动定位提示效果
posted @ 2009-05-18 14:02 cloudgamer 阅读(14522) 评论(81)  编辑 收藏 网摘 所属分类: Table, Javascript

  回复  引用    
#1楼2009-05-18 14:10 | pasttime[未注册用户]
非常不错
  回复  引用  查看    
#2楼2009-05-18 14:24 | 吉日嘎拉      
好文章,顶一下,支持。
  回复  引用  查看    
#3楼2009-05-18 14:38 | 爱上理财      
又见大侠心做了,不错
  回复  引用  查看    
#4楼2009-05-18 14:39 | KiNg.JiOnG      
不错,只是在firefox 中样式有点变了。
  回复  引用  查看    
#5楼2009-05-18 14:47 | 无忧      
楼主好色
  回复  引用  查看    
#6楼[楼主]2009-05-18 14:47 | cloudgamer      
@pasttime
@吉日嘎拉
@爱上理财
谢谢支持

@KiNg.JiOnG
那是博客的样式而已
不影响程序

  回复  引用  查看    
#7楼[楼主]2009-05-18 14:48 | cloudgamer      
@无忧
好色?

  回复  引用  查看    
#8楼2009-05-18 14:59 | winter-cn      
不错 cloudgamer写的东西都很实用啊
  回复  引用  查看    
#9楼[楼主]2009-05-18 15:10 | cloudgamer      
@winter-cn
客户需求当然要能用的了
呵呵
我就懂写写效果而已

  回复  引用    
#10楼2009-05-18 15:59 | testing530[未注册用户]
在IE5.5里没有效果
在IE6.0里滚动时,固定行会闪动

  回复  引用  查看    
#11楼[楼主]2009-05-18 16:03 | cloudgamer      
@testing530
ie5.5也来?我见都没见过呢
ie6因为不支持fixed所以会闪

  回复  引用  查看    
#12楼2009-05-18 16:09 | HOH      
我作的项目中,有个地方也要用到这么个功能,我是这么做的:
样式:
.Roll
{
position:relative ;
table-layout:fixed;
top:expression(this.offsetParent.scrollTop);
z-index: 10;
}
然后在行样式上加上:class='Roll'就可以了。

  回复  引用  查看    
#13楼[楼主]2009-05-18 16:13 | cloudgamer      
@HOH
我也想过position:relative
不过兼容性等等其他问题所以没有用到

  回复  引用  查看    
#14楼2009-05-18 16:45 | winter-cn      
@cloudgamer
其实你可以考虑在table外面套个容器 然后把固定的行放进外层容器中 这样就不会闪了

  回复  引用  查看    
#15楼[楼主]2009-05-18 16:54 | cloudgamer      
@winter-cn
不太明白
放在外层滚动的时候也要设置top的吧

  回复  引用  查看    
#16楼2009-05-18 17:03 | 无心雨云      
看看,走走,学学
  回复  引用  查看    
#17楼2009-05-18 17:03 | andy.wu      
果然术业有专攻啊
  回复  引用  查看    
#18楼2009-05-18 18:08 | 大豆男生      
好文章
  回复  引用    
#19楼2009-05-18 22:37 | Hand[未注册用户]
项目正好有此需要,多谢楼主的分享
  回复  引用  查看    
#20楼2009-05-18 23:23 | Carlos Zhao      
收藏了.
谢谢分享.

  回复  引用  查看    
#21楼[楼主]2009-05-18 23:40 | cloudgamer      
@无心雨云
@andy.wu
@大豆男生
@Hand
@Carlos Zhao
谢谢支持

  回复  引用    
#22楼2009-05-19 00:37 | myya[未注册用户]
楼主代码风格又有变化啊

  回复  引用  查看    
#23楼2009-05-19 00:41 | cssrain      
以前项目中遇到要 固定表头的,后来采用的是 如下解决方案:
<div>
表头
</div>

<div style="position:relative;height:300px;overflow:hidden;">
<div style="position:absolute;">
<table>
表内容
</table>
</div>
</div>

<div>
底部
</div>

中间内容使用 相对定位 和 绝对定位 。

呵呵,反正当时解决了客户的问题。

  回复  引用  查看    
#24楼2009-05-19 08:05 | Jertun      
http://news.cnblogs.com/n/43821/
看看这个吧,第14个,不需要你那么麻烦

  回复  引用  查看    
#25楼[楼主]2009-05-19 08:32 | cloudgamer      
@myya
谢谢支持

@cssrain
呵呵
研究一下

@Jertun
那个跟我这个不是一样的东西啊,只适合特定的情况特定的需求

  回复  引用  查看    
#26楼2009-05-19 08:47 | 小权子      
楼主弄得是不是相当于一个浮动窗体,里面显示了一个表头啊。
  回复  引用  查看    
#27楼[楼主]2009-05-19 08:53 | cloudgamer      
@小权子
是这个意思
但这个窗体比较特殊

  回复  引用  查看    
#28楼2009-05-19 09:10 | 紫色永恒      
牛贴!大师!
  回复  引用  查看    
#29楼2009-05-19 09:25 | bluesky4485      
很好的文章,仔细照着楼主做一遍,会学到不少东西。

@小权子
他那个并不一定是表头,可以是表中的任意一行的。

  回复  引用  查看    
#30楼[楼主]2009-05-19 09:35 | cloudgamer      
@紫色永恒
谢谢支持

@bluesky4485
文章终于有人欣赏 而不只是看效果 T_T

  回复  引用  查看    
#31楼2009-05-19 09:42 | 狼Robot      
IE8.0.7100.0
Firefox3.0.10
Opera9.27
我都试了,遗憾的是都没能看到楼主及各位所说的神奇效果.

  回复  引用  查看    
#32楼[楼主]2009-05-19 09:47 | cloudgamer      
@狼Robot
应该可以的哦
你下载实例看看

  回复  引用  查看    
#33楼2009-05-19 10:16 | zhwily      
收藏了.
谢谢分享.

  回复  引用    
#34楼2009-05-19 10:45 | Hand[未注册用户]
楼主,你的程序好象只能针对一行定位,不能针对多行定位,如果我的表头是由多行构成的,那就不行了.我尝试用数组来保存你的_oRow,_oRowTop,_oRotBottom等变量,然后通过循环,不过可惜都是不行的.不知道楼主能否指点一二呢?
  回复  引用  查看    
#35楼[楼主]2009-05-19 10:54 | cloudgamer      
@zhwily
谢谢支持

@Hand
其实关键就是把每个td的样式设置好
forEach(this._oRow.cells, Bind(this, function(o, i){
这里你换成
getElementsByTagName("td")试试

  回复  引用    
#36楼2009-05-19 14:18 | 楼主好色[未注册用户]
都是一些三点图片。。
  回复  引用  查看    
#37楼[楼主]2009-05-19 14:23 | cloudgamer      
@楼主好色
谁不好色,就当养眼呗

  回复  引用    
#38楼2009-05-19 15:41 | 剑无名[未注册用户]
呵呵,好文章,好技术。楼上的有些同学,食色性也,几张养眼的图片而已,用不着上纲上线吧?现实中那么多更黄更暴力的东西怎么没见大声疾呼?
  回复  引用    
#39楼2009-05-19 15:53 | 剑无名[未注册用户]
我在项目中也遇到过这样的需求,如23楼那样,将表格内容挖出来,放到div中,设置div的overflow-y属性为hidden。这样的效果是整个页面都不滚动,只有表格内容那部分滚动,也就解决了表头固定的问题。不过需要人为的固定表头和表内容的每列的对齐以保持美观。
  回复  引用  查看    
#40楼[楼主]2009-05-19 19:24 | cloudgamer      
@剑无名
呵呵
谢谢支持

  回复  引用  查看    
#41楼2009-05-20 10:20 | 楊彬      
写的不错.提一点我的意见:
你这可能存在这样一个缺陷:当Table栏位过多,要用到滚动条时,此Table的表头将不会水平滚动.

  回复  引用  查看    
#42楼[楼主]2009-05-20 10:31 | cloudgamer      
@楊彬
谢谢支持
这个不是列定位,水平会滚动才有问题吧
我这里是故意要水平不滚动的

  回复  引用    
#43楼2009-05-20 11:02 | 流浪江南
从无优赶过来了,一直跟踪着您的东西,惊叹,崇拜!

不知收不收学生?呵呵,要是能在您身上学个一招半式的就满足了!

  回复  引用    
#44楼2009-05-20 11:03 | 流浪江南
收学生吗?
  回复  引用  查看    
#45楼[楼主]2009-05-20 11:08 | cloudgamer      
@流浪江南
学生就不要了
有什么技术问题可以一起讨论:)

  回复  引用  查看    
#46楼2009-05-20 12:49 | 麦舒      
做得很不错!牛人!
  回复  引用  查看    
#47楼2009-05-21 09:10 | JerryZeng      
感谢楼主,前段时间也要做这个效果,而且还做了固定列的,只用了expression,所以就只支持IE了,而且还会抖动。

早出来这个就好啦。

对了,这个在IE6里面,那个新的table好像有点移位哦!

  回复  引用  查看    
#48楼[楼主]2009-05-21 09:32 | cloudgamer      
@JerryZeng
这里的我在ie6看没怎么移位哦
只是在ie6是会抖动
你的移位的情况是怎么样的呢

@麦舒
谢谢支持

  回复  引用    
#49楼2009-05-21 13:02 | 顺其自然[未注册用户]
真是佩服!
  回复  引用    
#50楼2009-05-23 01:37 | yiminghe
这个最好 table 里设置滚动条 ,不要依赖浏览器窗口滚动条,国外有个人实现的很好,纯css+xhtml,给你参考下吧,特别是在 firefox 中

代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>无滚动测试</title>
<style type="text/css">
<!--
/* 定义页面的基本样式 */
body { background: #FFF; color: #000;
font: normal normal 12px Verdana, Geneva, Arial, Helvetica, sans-serif;
margin: 10px; padding: 0;}
table, td, a { color: #000; font: normal normal 12px Verdana, Geneva, Arial, Helvetica, sans-serif;}
h1 { font: normal normal 18px Verdana, Geneva, Arial, Helvetica, sans-serif; margin: 0 0 5px 0}
h2 { font: normal normal 16px Verdana, Geneva, Arial, Helvetica, sans-serif; margin: 0 0 5px 0}
h3 { font: normal normal 13px Verdana, Geneva, Arial, Helvetica, sans-serif; color: #008000; margin: 0 0 15px 0}

/* 美化TH元素 */
thead.fixedHeader th { background: #C96; border-left: 1px solid #EB8;
border-right: 1px solid #B74; border-top: 1px solid #EB8; font-weight: normal;
padding: 4px 3px; text-align: left;}

/* 美化A元素,使表头能够点击 */
thead.fixedHeader a, thead.fixedHeader a:link, thead.fixedHeader a:visited
{ color: #FFF; display: block; text-decoration: none; width: 100%;}

/* 美化A元素,使表头能够点击 */
/* 警告: 在WinIE 6.x 下使用hover来切换背景可能会有问题 */
thead.fixedHeader a:hover
{ color: #FFF; display: block; text-decoration: underline; width: 100%;}

/* 美化TD元素,使表格行可以间隔显示 */
/* http://www.alistapart.com/articles/zebratables/ */
tbody.scrollContent td, tbody.scrollContent tr.normalRow td
{ background: #FFF; border-bottom: none; border-left: none;
border-right: 1px solid #CCC; border-top: 1px solid #DDD; padding: 2px 3px 3px 4px;}
tbody.scrollContent tr.alternateRow td
{ background: #EEE; border-bottom: none; border-left: none;
border-right: 1px solid #CCC; border-top: 1px solid #DDD; padding: 2px 3px 3px 4px;}
-->

<!-- 为遵守标准的浏览器实现卷动表格 -->

<!--
/* 创建一个有边的盒子(事实上是为了IE才需要这么做) */
div.tableContainer { clear: both; overflow: hidden;
width: 756px; height: 285px; border: 1px solid #963;}

/* 定义表格宽度,应该填满外面的容器 */
div.tableContainer table { width: 756px;}

/* 使THEAD元素有block级别的属性,对所有非IE浏览器 */
/* 使TBODY元素的overflow有用,对所有非IE、非Mozilla浏览器 */
thead.fixedHeader { display: block;}

/* 使表格内容可以卷动的定义 */
/* 使TBODY元素有block级别的属性,对所有非IE浏览器 */
/* 使TBODY元素的overflow有用,对所有非IE、非Mozilla浏览器 */
/* 导致的副作用是子节点的TD元素的width: auto属性不再有用了 ,重要对于firefox 单元格收缩了,但是tbody,thead没有收缩! */
tbody.scrollContent { display: block; height: 262px; overflow: auto; width: 100%;}

/* 分别定义第一、二、三个TH元素的宽度 */
/* 给最后一个TH加16px来填充滚动条的宽度,对所有非IE浏览器 */
/* http://www.w3.org/TR/REC-CSS2/selector.html#adjacent-selectors" target="_new">http://www.w3.org/TR/REC-CSS2/selector.html#adjacent-selectors */
thead.fixedHeader th { width: 200px}
thead.fixedHeader th + th { width: 240px}
thead.fixedHeader th + th + th { width: 316px}

/* 分别定义第一、二、三个TD元素的宽度 */
/* 对所有非IE浏览器 */
/* http://www.w3.org/TR/REC-CSS2/selector.html#adjacent-selectors" target="_new">http://www.w3.org/TR/REC-CSS2/selector.html#adjacent-selectors */
tbody.scrollContent td { width: 200px}
tbody.scrollContent td + td { width: 240px}
tbody.scrollContent td + td + td { width: 300px}
-->
</style>
<!-- 用表格外围容器的卷动来模拟在IE下的卷动效果 -->
<!--[if IE]>
<style type="text/css">

/* define height and width of scrollable area. Add 16px to width for scrollbar */
div.tableContainer {
clear: both;
height: 285px;
overflow: auto;
/*add by yiminghe ,禁止水平滚动条出现*/
overflow-x:hidden;
}

/* Fit the table inside the container. Width = table width + 16px scrollbar */
div.tableContainer table {
float: left;
width: 740px
}

/* Kill border on right side of table to prevent IE7 sidescrolling */
thead.fixedHeader, tbody.scrollContent {
border-right: none;
}

/* set table header to a fixed position. */
/* In WinIE 6.x, any element with a position property set to relative and is a child of */
/* an element that has an overflow property set, the relative value translates into fixed. */
/* Ex: parent element DIV with a class of tableContainer has an overflow property set to auto
很神奇,第一次知道overflow + relative == fix
*/
thead.fixedHeader tr {
position: relative
}

/* Make the table rows the correct height. */
/* Without this, they inherit the TABLE'S height, which is not what we want.
每个数据行会变得和table一样高
*/
tbody.scrollContent {
height: auto;
}
</style>

<![endif]-->
</head>
<body>
Pure CSS Scrollable Table with Fixed Header
<div id="tableContainer" class="tableContainer">
<table class="scrollTable" border="0" cellspacing="0" cellpadding="0" width="100%">
<thead class="fixedHeader">
<tr>
<th><a href="#">Header 1</a></th>
<th><a href="#">Header 2</a></th>
<th><a href="#">Header 3</a></th>
</tr>
</thead>
<tbody class="scrollContent">
<tr>
<td>Cell Content 1</td>
<td>Cell Content 2</td>
<td>Cell Content 3</td>
</tr>
<tr>
<td>More Cell Content 1</td>
<td>More Cell Content 2</td>
<td>More Cell Content 3</td>
</tr>
<tr>
<td>Even More Cell Content 1</td>
<td>Even More Cell Content 2</td>
<td>Even More Cell Content 3</td>
</tr>
<tr>
<td>And Repeat 1</td>
<td>And Repeat 2</td>
<td>And Repeat 3</td>
</tr>
<tr>
<td>Cell Content 1</td>
<td>Cell Content 2</td>
<td>Cell Content 3</td>
</tr>
<tr>
<td>More Cell Content 1</td>
<td>More Cell Content 2</td>
<td>More Cell Content 3</td>
</tr>
<tr>
<td>Even More Cell Content 1</td>
<td>Even More Cell Content 2</td>
<td>Even More Cell Content 3</td>
</tr>
<tr>
<td>And Repeat 1</td>
<td>And Repeat 2</td>
<td>And Repeat 3</td>
</tr>
<tr>
<td>Cell Content 1</td>
<td>Cell Content 2</td>
<td>Cell Content 3</td>
</tr>
<tr>
<td>More Cell Content 1</td>
<td>More Cell Content 2</td>
<td>More Cell Content 3</td>
</tr>
<tr>
<td>Even More Cell Content 1</td>
<td>Even More Cell Content 2</td>
<td>Even More Cell Content 3</td>
</tr>
<tr>
<td>And Repeat 1</td>
<td>And Repeat 2</td>
<td>And Repeat 3</td>
</tr>
<tr>
<td>Cell Content 1</td>
<td>Cell Content 2</td>
<td>Cell Content 3</td>
</tr>
<tr>
<td>More Cell Content 1</td>
<td>More Cell Content 2</td>
<td>More Cell Content 3</td>
</tr>
<tr>
<td>Even More Cell Content 1</td>
<td>Even More Cell Content 2</td>
<td>Even More Cell Content 3</td>
</tr>
<tr>
<td>And Repeat 1</td>
<td>And Repeat 2</td>
<td>And Repeat 3</td>
</tr>
<tr>
<td>Cell Content 1</td>
<td>Cell Content 2</td>
<td>Cell Content 3</td>
</tr>
<tr>
<td>More Cell Content 1</td>
<td>More Cell Content 2</td>
<td>More Cell Content 3</td>
</tr>
<tr>
<td>Even More Cell Content 1</td>
<td>Even More Cell Content 2</td>
<td>Even More Cell Content 3</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

  回复  引用  查看    
#51楼[楼主]2009-05-23 08:32 | cloudgamer      
@yiminghe
需求不一样
何必用固有的东西限制自己呢
我也知道类似这样固定表头的做法,可我就是不想做一样的东西

  回复  引用    
#52楼2009-05-23 13:04 | yiminghe[未注册用户]
--引用--------------------------------------------------
cloudgamer: @yiminghe

需求不一样

何必用固有的东西限制自己呢

我也知道类似这样固定表头的做法,可我就是不想做一样的东西
--------------------------------------------------------
你确实比我层次高哦,我尚处于模仿阶段,还没达到创新阶段,自己汗一下

  回复  引用  查看    
#53楼[楼主]2009-05-23 13:57 | cloudgamer      
@yiminghe
我也不是多创新
这里很多效果都已经有类似的东西
但可以说全部都起码有一部分我自己的东西
每一步都有我自己的想法,虽然有时未必能表达出来

  回复  引用  查看    
#54楼2009-06-07 11:28 | 好俊的功夫啊      
我感觉楼主写得太复杂了,是否可以简化一下,做个精简版的,只实现行头固定,其它什么下拉框,自动生成序号都不要了,js 也简化一下,一大堆看了头痛啊

见笑了

  回复  引用  查看    
#55楼[楼主]2009-06-07 12:40 | cloudgamer      
@好俊的功夫啊
我想你需要的是50楼那样的吧
我这个也不适合你

  回复  引用  查看    
#56楼2009-06-08 17:40 | 好俊的功夫啊      
我不喜欢五十楼的,我更喜欢你这个,只是我不需要那些自动序号和下拉框嘛,

顺便问下,假如我要固定的是第二行,那要修改哪里?

感谢楼主提供这么好用的东西

  回复  引用  查看    
#57楼[楼主]2009-06-08 17:46 | cloudgamer      
@好俊的功夫啊
自动序号和下拉框是我用来测试效果的而已
跟主程序没有关系的啊
TableFixed 才是程序本身

固定第二行把Index设为1(索引)

  回复  引用  查看    
#58楼2009-06-08 20:08 | 好俊的功夫啊      
测试了二个问题
1 导出数据全乱了,本来报表有五行导出后只有二行,而且列错乱了,我是Winform下用WebBrowser来显示报表,再导出的
2 假如页面是左右二部分组成的,左边是菜单,右边是报表,选择报表并生成后,滚动正常, 但当我把左边隐藏了,页面的左右部分的宽度变下,再滚动问题就出来了,没有随宽度变化而调整新表的 Left

第一个问题比较严重,报表一般都是要导出的,假如这个没办法满足,报表意义不大了,希望再改进下。楼主辛苦辛苦

我们这些用现成的只有尽量帮楼主找出问题,完善起来才是最重要的。

  回复  引用  查看    
#59楼[楼主]2009-06-09 08:30 | cloudgamer      
@好俊的功夫啊
报表的话貌似跟程序关系不大吧
第二个问题可以隐藏时执行一下SetPos

  回复  引用    
#60楼2009-06-20 11:15 | 潘凯[未注册用户]
楼主,问个不想关的问题
我从后台获得了一些数据,数据量比较大
当我把这些数据格式化后,用document.getElementById("xx").innerHTML = "格式化后的数据"时,这步非常消耗时间,怎么解决啊?
我目前的操作类似于下面:
var arr = [];
arr.push("<table><tbody><tr>");
for(var i = 0 ; i < 1000 ; i++){
arr.push("<td><input/></td><td><label>label</label></td><td><span>span</span></td><td><input type='checkbox' value='ck'/></td><td><select><option value='1'>1</option><option value='2'>2</option></select></td><td><input type='submit' value='submit'/></td><td><a href='javascript:void(0)' onclick='alert(3434)'>href</a></td>");
if((i+1)%2 == 0) arr.push("</tr><tr>");
}
arr.push("</tr></tbody></table>");
document.getElementById("xx") = arr.join(""); //这里很消耗时间

  回复  引用  查看    
#61楼[楼主]2009-06-20 17:26 | cloudgamer      
@潘凯
innerHTML 已经是最快的了
要更快的话我也不知道哦

  回复  引用    
#62楼2009-06-28 15:02 | wzx[未注册用户]
@cloudgamer
同意您的观点.

  回复  引用    
#63楼2009-07-08 12:23 | yegle[未注册用户]
有个bug,fx3.5中,如果选了一个select之后,再往下拖动,固定的将是刚才选择的那个select
  回复  引用  查看    
#64楼[楼主]2009-07-08 13:49 | cloudgamer      
@yegle
那时故意做的效果
点击行选择克隆行

  回复  引用    
#65楼2009-07-08 21:10 | yegle[未注册用户]
@cloudgamer
啊……原来是feature~

  回复  引用  查看    
#66楼2009-07-14 10:17 | Ling.Mary.Ma      
感谢,感谢,目前正在被这个行列固定问题困扰着。
ie6确实有些移位
当滚动时,表头像右侧平移了大概一个像素左右的距离

  回复  引用  查看    
#67楼[楼主]2009-07-14 14:26 | cloudgamer      
@Ling.Mary.Ma
我用ietest测试好像没有哦

  回复  引用    
#68楼2009-07-26 17:24 | any13678[未注册用户]
嗯,很不错,学习了,谢谢楼主了
  回复  引用    
#69楼2009-09-27 14:15 | demon111[未注册用户]
支持楼主!
贪婪的问一下,行定位结合列定位的什么时候放出来啊?

  回复  引用  查看    
#70楼[楼主]2009-09-29 08:35 | cloudgamer      
@demon111
看有需求或时间再做吧

@any13678
谢谢支持

  回复  引用    
#71楼2009-11-25 17:42 | 风顠无痕[未注册用户]
LZ你是把TABLE放在一个BODY里的 我想放在一个DIV中不知道需要改动哪些地方 研究了几天还是没改好 请不零吝主赐教
  回复  引用  查看    
#72楼[楼主]2009-11-25 21:58 | cloudgamer      
@风顠无痕
div的话就更简单啦
不用复制直接用原来的div做浮动就行了

  回复  引用    
#73楼2009-11-26 10:19 | 风顠无痕[未注册用户]
@cloudgamer
LZ我想你是理解错了我的意思了.
我的意思是
<body>
<p></P>
<p></P>
<p></P>
<div> //此div是可以设置高度和宽度 相当于你原来
程序中的body
<table> //要的就是这个table中的表头固定
</table>
<div>
</body>



我的QQ是158709965 邮箱:lywy510@qq.com
希望你能指点我一下 成分感谢

  回复  引用    
#74楼2009-11-26 10:21 | 风顠无痕[未注册用户]
刚才我想打的是万分感谢 打错了 呵呵
  回复  引用    
#75楼2009-11-26 10:22 | 风顠无痕[未注册用户]
我想用现在的div的高度换你原来的client高度 一直没有成功
  回复  引用  查看    
#76楼[楼主]2009-11-26 13:36 | cloudgamer      
@风顠无痕
我想你要的效果是50楼那种
自己研究一下吧

  回复  引用    
#77楼2009-11-26 14:56 | 风顠无痕[未注册用户]
50楼的不兼容IE8
  回复  引用  查看    
#78楼[楼主]2009-11-26 16:14 | cloudgamer      
@风顠无痕
去这里找找吧
http://www.open-open.com/ajax/Grid.htm
其余就请自己研究了

  回复  引用    
#79楼2009-11-30 11:05 | 风顠无痕[未注册用户]
非常感谢
  回复  引用    
#80楼2009-12-17 10:40 | 陈素龙[未注册用户]
如果表头<thead />中有两行,一行带rowspan呢?
  回复  引用  查看    
#81楼[楼主]2009-12-17 13:51 | cloudgamer      
@陈素龙
这就不好做了
可能要难很多了,那时也没研究,没想到怎么做

@风顠无痕
谢谢支持