【获取背景色】
如果td是背景透明的话显然不太美观,最好是找一个合适的颜色来填充。 程序用的方法是,从当前td开始找,如果背景是透明的话,就再从父节点中找,直到找到有背景色为止。 一般来说透明的属性值是"transparent",但在chrome里却是"rgba(0, 0, 0, 0)",所以用了一个属性来保存透明值: this._transparent = isChrome ? "rgba(0, 0, 0, 0)" : "transparent"; 并在GetBgColor获取背景色程序中使用: while (bgc == this._transparent && (node = node.parentNode) != document) { bgc = CurrentStyle(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. http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-1060184317 很简单,就是节点的父节点,看过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. http://www.w3.org/TR/cssom-view/#elementview-offsetparent 这里主要有四点: 1,如果是根元素、body元素或元素的position是fixed,将返回null; 2,如果是area元素,会返回最接近的map元素; 3,返回至少符合以下一个条件的最接近该节点的元素:1,元素的position不是static;2,是body元素;3,源元素的position是static,祖先元素中的以下元素:td,th或table。 4,返回null。 其中第三点是最常见的情况,详细可以看下面的测试: <!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"> <body> <table width="100" id="t"> <tr> <td> <div id="t1"> </div> </td> <td id="t2"> <div style="position:absolute;"> <div id="t3"> </div> </div> </td> </tr> </table> <div id="t4" style="position:fixed;"> </div> <script> var $ = function (id) { return "string" == typeof id ? document.getElementById(id) : id; };
alert($("t").offsetParent)//body alert($("t1").offsetParent)//td alert($("t2").offsetParent)//table alert($("t3").offsetParent)//div alert($("t4").offsetParent)//null </script> </body> </html> 可见offsetParent跟parentNode的区别还是很大的。
而parentNode跟parentElement除了前者是w3c标准,后者只ie支持,其他的区别就不是那么明显了。 在ie中大部分情况下两者的效果是一样的,当然如果是一模一样的话ie就没必要弄这么一个东西出来了,测试下面的代码: <!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"> <body> <script> var o = document.createDocumentFragment().appendChild(document.createElement("div")); alert(o.parentNode) alert(o.parentNode.nodeType)//11 alert(o.parentElement)//null
alert(document.body.parentNode) alert(document.body.parentNode.nodeType)//1 alert(document.body.parentElement)//html
alert(document.body.parentNode.parentNode) alert(document.body.parentNode.parentNode.nodeType)//9 alert(document.body.parentElement.parentElement)//null </script> </body> </html> 可以看到当父节点的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基本没戏,而且在这个效果中即使是差了1px也会看不舒服。 对于支持defaultView的当然可以直接获取,否则就用上面的方法3来获取: style.width = (document.defaultView ? parseFloat(css.width) : (o.clientWidth - parseInt(css.paddingLeft) - parseInt(css.paddingRight))) + "px"; 但这里不管哪个方法都有一个问题,就是出现scroll的情况,不过还好td这个元素即使设置了overflow为scroll也不会出现滚动条,除了ie8和chrome。 程序没对这个情况做处理,毕竟给td设scroll也不常见,而且支持这个的浏览器不多,没必要花太多时间在这里。 ps:关于td宽度的自动调整可以参考w3c的table-layout部分。 http://www.w3.org/TR/CSS2/tables.html#width-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. https://developer.mozilla.org/pt/CSS/border-collapse 意思是在collapse border模型中,相邻的td会共用边框。看下面的例子会更明白: <!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"> <body> <style type="text/css"> .t{line-height:40px;width:200px; } .t td{border:5px solid #999;} </style> <table class="t" style="border-collapse:collapse;"> <tr> <td width="50"> </td> <td style="border-left-width:10px; border-left-style:dotted;"> </td> <td width="50"> </td> </tr> </table> <table class="t"> <tr> <td width="50"> </td> <td style="border-left-width:10px; border-left-style:dotted;"> </td> <td width="50"> </td> </tr> </table> </body> </html> 可以看到使用collapse之后,相邻td的边框都合并成一条而且是以相邻边框中宽度较大的那条为准。 那td跟table之间呢,参考下面的例子: <!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"> <body> <style type="text/css"> .t{line-height:40px;width:200px;border-collapse:collapse;} .t td{border:5px solid #999;} </style> <table class="t" id="t1"> <tr> <td width="50" style="border-left:10px dotted #999;"> </td> <td> </td> <td width="50"> </td> </tr> </table> <br /> <table class="t" id="t2" style="border-left:10px dotted #999;"> <tr> <td width="50"> </td> <td> </td> <td width="50"> </td> </tr> </table> </body> </html> 可见table和td之间也是遵从同样规则。 还有的是当设置了collapse那cellspacing就无效了。顺便说说border-spacing,它其实就是cellspacing在css中的样式形式,只是ie在ie8才开始支持,详细可以看mozilla的说明。 https://developer.mozilla.org/En/CSS/Border-spacing
collapse的一个常见应用是做边框表格,例如1px边框的表格: <!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"> <body> <style type="text/css"> .t{line-height:40px;width:200px;}
.t1{border-collapse:collapse;} .t1 td{border:1px solid #999;}
.t2{background-color:#999;} .t2 td{background-color:#FFF;} </style> <table class="t t1"> <tr> <td width="50"> </td> <td> </td> <td width="50"> </td> </tr> </table> <table class="t t2" cellspacing="1"> <tr> <td width="50"> </td> <td> </td> <td width="50"> </td> </tr> </table> </body> </html> 前者用的collapse,后者是用table背景色模拟,虽然效果都一样,但前者显然较好,才是真正的“边框”。
在使用了collapse之后,要写一个通用的获取边框宽度程序会变得十分麻烦,而且有些情况下甚至没办法判断获取。 详细情况这里就不细说了,有兴趣研究的话可以看看w3c的The collapsing border model,当然要想全部了解的话还要在各个浏览器中研究。 http://www.w3.org/TR/CSS2/tables.html#collapsing-borders 【元素位置】
table的样式设置好后,还需要获取原table和tr的位置参数,为后面的元素定位做准备。 要获取某个元素的相对文档的位置,传统的做法是获取对象的offsetLeft/offsetTop,然后分别加上offsetParent的offsetLeft/offsetTop,直到找不到offsetParent为止。 得到的结果就是相对文档的位置了,上面已经介绍过offsetParent,原理应该都明白了吧。 程序的SetRect设置区域属性方法中也使用了这个思路: //获取原table位置 var o = this._oTable, iLeft = o.offsetLeft, iTop = o.offsetTop; while (o.offsetParent) { o = o.offsetParent; iLeft += o.offsetLeft; iTop += o.offsetTop; } this._oTableLeft = iLeft; this._oTableTop = iTop; this._oTableBottom = iTop + this._oTableHeight; //获取原tr位置 o = this._oRow; iTop = o.offsetTop; while (o.offsetParent) { o = o.offsetParent; iTop += o.offsetTop; } this._oRowTop = iTop; this._oRowBottom = iTop + this._oRow.offsetHeight;
不过这里介绍一个更好的方法,通过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... https://developer.mozilla.org/En/DOM/Element.getBoundingClientRect 返回一个TextRectangle对象,包含left, top, right和bottom几个只读属性,以px为单位来表示边界框相对视窗左上角的位置。(偶英文烂啊) 要注意是相对视窗,不是文档,如果要相对文档还必须加上scrollLeft/scrollTop。 通过下面的测试可以看到两个方法返回的结果都是相同的: <!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"> <body> <style type="text/css"> .t{line-height:40px;width:200px; border:10px solid; margin-top:900px; margin-left:500px;} </style> <div class="t" id="t"> </div> <script> var o = document.getElementById("t");
var rect = o.getBoundingClientRect(); var iLeft1 = rect.left + document.documentElement.scrollLeft, iTop1 = rect.top + document.documentElement.scrollTop;
var iLeft2 = o.offsetLeft, iTop2 = o.offsetTop; while (o.offsetParent) { o = o.offsetParent; iLeft2 += o.offsetLeft; iTop2 += o.offsetTop; }
alert(iLeft1+"_"+iLeft2) alert(iTop1+"_"+iTop2) </script> </body> </html>
程序中如果支持getBoundingClientRect就会用它来获取位置参数: //用getBoundingClientRect获取原table位置 var top = this._doc.scrollTop, rect = this._oTable.getBoundingClientRect(); this._oTableLeft = rect.left + this._doc.scrollLeft; this._oTableTop = rect.top + top; this._oTableBottom = rect.bottom + top; //获取原tr位置 rect = this._oRow.getBoundingClientRect(); this._oRowTop = rect.top + top; this._oRowBottom = rect.bottom + top;
明显用getBoundingClientRect更方便快捷。 这个方法虽然是ie的产物,但已经是w3c的标准,而且ff3和Opera都已经支持了这个方法,基本可以放心使用,除了chrome。 这里只是简单介绍,想了解更多可以看w3c的View Module部分。 http://www.w3.org/TR/cssom-view/#the-getclientrects
获取原table和tr的位置后,还需要计算新table的位置。 程序可以自定义新table位于视窗位置的百分比,例如顶部是0,中间是0.5,底部是1,可以在程序初始化时或调用SetPos方法设置。 这里主要获取视窗高度和新table在视窗的top值: this._viewHeight = document.documentElement.clientHeight; this._ntViewTop = (this._viewHeight - this._nTableHeight) * this._pos; 定位范围实际上是从视框顶部到视框高度减去新table高度的范围内的,所以计算时要先把视窗高度减去新table的高度。
【元素定位】
万事俱备,只欠定位了。 由于要根据窗口滚动状态来判断计算定位,scrollTop/scrollLeft的获取必不可少。 但在chrome中就算用了DOCTYPE,也要用document.body来获取scrollTop/scrollLeft,尽管它确实有document.documentElement。 对chrome了解不多,也不知哪里能查它的相关文档,程序里就直接做个判断算了: this._doc = isChrome ? document.body : document.documentElement;
定位的第一步就是判断是否需要定位,这里的判断标准有两个,第一个是原tr是否超过了视窗范围,还有是新table要显示的位置是否在原table的显示范围内。 第一点可以通过原tr位置的顶部和底部是否超过视窗的顶部和底部来判断: var top = this._doc.scrollTop, left = this._doc.scrollLeft ,outViewTop = this._oRowTop < top, outViewBottom = this._oRowBottom > top + this._viewHeight; if(outViewTop || outViewBottom){...}
在看第二点之前先看看程序中的Auto属性,它是用来指定否自动定位的。 如果自动定位的话当原tr离开视框顶部新table就会定位到视框顶部,离开底部新table就会定位到视框底部,这样看上去会比较自然。 如果不选择自动的话就会根据SetPos方法中计算得到的新table视窗top值来设置定位: var viewTop = !this.Auto ? this._nTableViewTop : (outViewTop ? 0 : (this._viewHeight - this._nTableHeight))//视窗top ,posTop = viewTop + top;//位置top
接着就判断新table要显示的位置是否在原table的显示范围内,这个可以通过新table位置的顶部和底部是否超过原table的顶部和底部来判断。 if(posTop > this._oTableTop && posTop + this._nTableHeight < this._oTableBottom){...}
当符合所有的条件就可以进行定位了,fixed定位的要使用相对视窗的top值: this._style.top = viewTop + "px"; this._style.left = this._oTableLeft - left + "px"; 像ie6是absolute定位的就使用相对文档的top值: this._style.top = posTop + "px"; this._style.left = this._oTableLeft + "px"; 注意考虑到左右滚动,所以left也必须设置。
当然不符合条件就会隐藏新table,程序中给top设置一个很大的负值来间接“隐藏”它。 用负值是因为这样不会把ie6的页面拉长,不用display是因为上面需要获取它的offsetHeight,如果用display隐藏就获取不了啦。
最后把Run程序绑定到window的scroll事件中就可以了,而window在resize时视框高度会发生变化,所以resize要绑定的是SetPos。
【覆盖select】
只要用到了定位,就不得不面对一个老对手“ie6的select”。 我在之前的文章也介绍过一些解决方法(参考这里的覆盖select),这里不能直接隐藏select,那看来只能用iframe了。 但用iframe有一个很大的问题,在ie6测试下面的代码,并拖动滚动条: <!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"> <body> <style type="text/css"> body{height:1000px;} .t{height:300px;width:200px; border:1px solid; position:absolute; background:#FFF;top:0;left:0;} </style> <iframe class="t" id="t"> </iframe> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> <select> </select> <br /> </body> </html> 可以看到,即使是iframe,在拖动滚动条的时候,select仍然在后面闪啊闪,在本程序中这个现象会尤其明显。 看来还得用隐藏select的方法,最好的做法是只隐藏在新table后面的select,而不影响其他select的正常显示。 那关键就是如何判断select是否在新table后面,这个可以通过位置坐标判断,刚好可以用到上面的getBoundingClientRect。 一般的思路是判断新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的: this.ResetSelect(); var rect = this._nTable.getBoundingClientRect(); //把需要隐藏的放到_selects集合 this._selects = Filter(this._oTable.getElementsByTagName("select"), Bind(this, function(o){ var r = o.getBoundingClientRect(); if(r.top <= rect.bottom && r.bottom >= rect.top){ o._count ? o._count++ : (o._count = 1);//防止多个实例冲突 //设置隐藏 var visi = o.style.visibility; if(visi != "hidden"){ o._css = visi; o.style.visibility = "hidden"; }
return true; } }))
其中ResetSelect方法是用来恢复显示select的: forEach(this._selects, function(o){ !--o._count && (o.style.visibility = o._css); }); this._selects = [];
但这个方法在快速滚屏时还是无能为力,而且select越多效率也随之下降,各位有更好方法的话欢迎交流。
【Chrome一个bug】
在测试的时候发现Chrome一个bug,测试下面代码: <!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"> <body> <table border="1"> <tr> <td id="tt"> </td> </tr> </table> <div id="t"> </div> <script> document.getElementById("t").offsetWidth; document.getElementById("tt").innerHTML = " <select> <option>test </option> </select>"; </script> </body> </html> 一个毫不相干的操作居然令table没有自动撑开,加上前面的问题,看来Chrome的路还很长啊。
使用说明
实例化一个TableFixed对象只需要一个参数table的id: new TableFixed("idTable");
实例化时有4个可选属性: Index: 0,//tr索引 Auto: true,//是否自动定位 Pos: 0,//自定义定位位置百分比(0到1) Hide: false//是否隐藏(不显示)
其中Index和Pos在实例化之后就不能使用。 要修改克隆行可以用Clone方法,其参数是要克隆tr的索引。 要修改自定义定位位置可以用SetPos方法,其参数是要定位的位置百分比。
具体使用请参考实例。 程序源码
-
JScript code
-
var
TableFixed
=
function
(table, options){
this
._oTable
=
$(table);
//
原table
this
._nTable
=
this
._oTable.cloneNode(
false
);
//
新table
this
._nTable.id
=
""
;
//
避免id冲突
this
._oTableLeft
=
this
._oTableTop
=
this
._oTableBottom
=
0
;
//
记录原table坐标参数
this
._oRowTop
=
this
._oRowBottom
=
0
;
//
记录原tr坐标参数
this
._viewHeight
=
this
._oTableHeight
=
this
._nTableHeight
=
0
;
//
记录高度
this
._nTableViewTop
=
0
;
//
记录新table视框top
this
._selects
=
[];
//
select集合,用于ie6覆盖select
this
._style
=
this
._nTable.style;
//
用于简化代码
//
chrome的scroll用document.body
this
._doc
=
isChrome
?
document.body : document.documentElement;
//
chrome透明用rgba(0, 0, 0, 0)
this
._transparent
=
isChrome
?
"
rgba(0, 0, 0, 0)
"
:
"
transparent
"
;
this
.SetOptions(options);
this
._index
=
this
.options.Index;
this
._pos
=
this
.options.Pos;
this
.Auto
=
!!
this
.options.Auto;
this
.Hide
=
!!
this
.options.Hide; addEventHandler(window,
"
resize
"
, Bind(
this
,
this
.SetPos)); addEventHandler(window,
"
scroll
"
, Bind(
this
,
this
.Run));
this
._oTable.parentNode.insertBefore(
this
._nTable,
this
._oTable);
this
.Clone(); }; TableFixed.prototype
=
{
//
设置默认属性
SetOptions:
function
(options) {
this
.options
=
{
//
默认值
Index:
0
,
//
tr索引
Auto:
true
,
//
是否自动定位
Pos:
0
,
//
自定义定位位置百分比(0到1)
Hide:
false
//
是否隐藏(不显示)
}; Extend(
this
.options, options
||
{}); },
//
克隆表格
Clone:
function
(index) {
//
设置table样式
this
._style.width
=
this
._oTable.offsetWidth
+
"
px
"
;
this
._style.position
=
isIE6
?
"
absolute
"
:
"
fixed
"
;
this
._style.zIndex
=
100
;
//
设置index
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
);
if
(oT.parentNode
!=
this
._oTable){ nT
=
oT.parentNode.cloneNode(
false
).appendChild(nT).parentNode; }
//
插入新行
if
(
this
._nTable.firstChild){
this
._nTable.replaceChild(nT,
this
._nTable.firstChild); }
else
{
this
._nTable.appendChild(nT); }
//
去掉table上面和下面的边框
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
;
//
设置td样式
var
nTds
=
this
._nTable.rows[
0
].cells; forEach(
this
._oRow.cells, Bind(
this
,
function
(o, i){
var
css
=
CurrentStyle(o), style
=
nTds[i].style;
//
设置td背景
style.backgroundColor
=
this
.GetBgColor(o, css.backgroundColor);
//
设置td的width,没考虑ie8/chrome设scroll的情况
style.width
=
(document.defaultView
?
parseFloat(css.width) : (o.clientWidth
-
parseInt(css.paddingLeft)
-
parseInt(css.paddingRight)))
+
"
px
"
; }));
//
获取table高度
this
._oTableHeight
=
this
._oTable.offsetHeight;
this
._nTableHeight
=
this
._nTable.offsetHeight;
this
.SetRect();
this
.SetPos(); },
//
获取背景色
GetBgColor:
function
(node, bgc) {
//
不要透明背景(没考虑图片背景)
while
(bgc
==
this
._transparent
&&
(node
=
node.parentNode)
!=
document) { bgc
=
CurrentStyle(node).backgroundColor; }
return
bgc
==
this
._transparent
?
"
#fff
"
: bgc; },
//
设置坐标属性
SetRect:
function
() {
if
(
this
._oTable.getBoundingClientRect){
//
用getBoundingClientRect获取原table位置
var
top
=
this
._doc.scrollTop, rect
=
this
._oTable.getBoundingClientRect();
this
._oTableLeft
=
rect.left
+
this
._doc.scrollLeft;
this
._oTableTop
=
rect.top
+
top;
this
._oTableBottom
=
rect.bottom
+
top;
//
获取原tr位置
rect
=
this
._oRow.getBoundingClientRect();
this
._oRowTop
=
rect.top
+
top;
this
._oRowBottom
=
rect.bottom
+
top; }
else
{
//
chrome不支持getBoundingClientRect
//
获取原table位置
var
o
=
this
._oTable, iLeft
=
o.offsetLeft, iTop
=
o.offsetTop;
while
(o.offsetParent) { o
=
o.offsetParent; iLeft
+=
o.offsetLeft; iTop
+=
o.offsetTop; }
this
._oTableLeft
=
iLeft;
this
._oTableTop
=
iTop;
this
._oTableBottom
=
iTop
+
this
._oTableHeight;
//
获取原tr位置
o
=
this
._oRow; iTop
=
o.offsetTop;
while
(o.offsetParent) { o
=
o.offsetParent; iTop
+=
o.offsetTop; }
this
._oRowTop
=
iTop;
this
._oRowBottom
=
iTop
+
this
._oRow.offsetHeight; } },
//
设置新table位置属性
SetPos:
function
(pos) {
//
设置pos
this
._pos
=
Math.max(
0
, Math.min(
1
, isNaN(pos)
?
this
._pos : pos));
//
获取位置
this
._viewHeight
=
document.documentElement.clientHeight;
this
._nTableViewTop
=
(
this
._viewHeight
-
this
._nTableHeight)
*
this
._pos;
this
.Run(); },
//
运行
Run:
function
() {
if
(
!
this
.Hide){
var
top
=
this
._doc.scrollTop, left
=
this
._doc.scrollLeft
//
原tr是否超过顶部和底部
,outViewTop
=
this
._oRowTop
<
top, outViewBottom
=
this
._oRowBottom
>
top
+
this
._viewHeight;
//
原tr超过视窗范围
if
(outViewTop
||
outViewBottom){
var
viewTop
=
!
this
.Auto
?
this
._nTableViewTop : (outViewTop
?
0
: (
this
._viewHeight
-
this
._nTableHeight))
//
视窗top
,posTop
=
viewTop
+
top;
//
位置top
//
在原table范围内
if
(posTop
>
this
._oTableTop
&&
posTop
+
this
._nTableHeight
<
this
._oTableBottom){
//
定位
if
(isIE6){
this
._style.top
=
posTop
+
"
px
"
;
this
._style.left
=
this
._oTableLeft
+
"
px
"
; setTimeout(Bind(
this
,
this
.SetSelect),
0
);
//
iebug
}
else
{
this
._style.top
=
viewTop
+
"
px
"
;
this
._style.left
=
this
._oTableLeft
-
left
+
"
px
"
; }
return
; } } }
//
隐藏
this
._style.top
=
"
-99999px
"
; isIE6
&&
this
.ResetSelect(); },
//
设置select集合
SetSelect:
function
() {
this
.ResetSelect();
var
rect
=
this
._nTable.getBoundingClientRect();
//
把需要隐藏的放到_selects集合
this
._selects
=
Filter(
this
._oTable.getElementsByTagName(
"
select
"
), Bind(
this
,
function
(o){
var
r
=
o.getBoundingClientRect();
if
(r.top
<=
rect.bottom
&&
r.bottom
>=
rect.top){ o._count
?
o._count
++
: (o._count
=
1
);
//
防止多个实例冲突
//
设置隐藏
var
visi
=
o.style.visibility;
if
(visi
!=
"
hidden
"
){ o._css
=
visi; o.style.visibility
=
"
hidden
"
; }
return
true
; } })) },
//
恢复select样式
ResetSelect:
function
() { forEach(
this
._selects,
function
(o){
!--
o._count
&&
(o.style.visibility
=
o._css); });
this
._selects
=
[]; } };
|