摘要:在使用表格显示数据时我们经常会遇到数据过多无法一屏完全显示的问题,这个时候我们就会给用户显示滚动条来拖动。但是多数情况下表格是带有表头的,纵向拖动往往就看不到表头;而横向拖动又会出现看不到主题列(例如统计某人基本信息时姓名就是主题列),这个时候怎么办呢?答案就是行列锁定。
主要内容:
1.行列锁定的常用方法
2.IE下实现行列锁定
3.使用jQuery开发一个简单的行列锁定插件
一、行列锁定的常用方法
从使用上来看,要实现行列锁定的效果无非就是使用第三方组件和自己从零做起一步步实现。第三方组件一般比较强大,除了行列锁定的功能之外一般还包括排序、筛选等(例如Ext的Locking-grid扩展组件),但是使用第三方组件也会造成一些其他的问题,或者说有些时候你根本就没有办法使用第三方组件(我遇到的就是这种情况)。今天我们主要讨论的是如何利用基本的html来自己实现行列锁定。自己实现table锁定行列的方法基本上有两种:一种是利用多个table拼接,最终"拼"成一个大的table。这种情况一般将表头和主题列分别放到单独的table中,数据行放到另一个table,拖动数据所在的table时利用js动态实现其他table的同步拖动。第二种就是利用单独的table,通过设置table行和列相对位置来实现行列锁定。两种方式相比较而言,第一种的方式更加容易控制一些,而且由于它将一个大表格分散到多个table中更有利于完成其他复杂功能;第二种实现比第一种效果要好一些,而且更有利于封装和扩展。由于我所遇到的情况是必须在原有html基础上实现行列锁定,因此这里就主要说一下第二种方式。
二、IE下实现行列锁定
由于我们下面说的方法主要利用tr、td的position:relative样式,而在新的css标准中没有对tr进行position:relative定义,因此除了IE在firefox4、chrome等新版本浏览器中都无法使用我们下面所说的方法(事实上IE9也是使用新标准,只不过其对兼容性做了处理,因此我们这种方法基本在IE所有版本中都是可行的)。我们的实现原理很简单:首先在table最外层包装一个div用来显示滚动条,接着设置tr和td的position和z-index样式控制其相对显示,然后在滚动的时候动态修改tr和td的top和left属性使其相对位置保持不表。下面我们来看一下具体的实现:
<!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> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Table锁定行列</title> <mce:style type="text/css"><!-- .LockRow /*固定行的样式*/ { position: relative; top: expression(this.parentElement.parentElement.parentElement.scrollTop); /*top:0px;*/ z-index:2; } .LockCell /*固定列的样式*/ { position: relative; left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft); /*left:0px;*/ z-index:0; } .LockCross /*行列交叉处样式*/ { z-index:3; } .divBoxing /*外出div样式*/ { clear:both; overflow: scroll; position:relative; } .tbLock /*设置单元格间隙的样式*/ { border-collapse:collapse; } .lockRowBg { background-color:#CFF; } .lockColumnBg { background-color:#CFF; } --></mce:style><style type="text/css" mce_bogus="1">.LockRow /*固定行的样式*/ { position: relative; top: expression(this.parentElement.parentElement.parentElement.scrollTop); /*top:0px;*/ z-index:2; } .LockCell /*固定列的样式*/ { position: relative; left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft); /*left:0px;*/ z-index:0; } .LockCross /*行列交叉处样式*/ { z-index:3; } .divBoxing /*外出div样式*/ { clear:both; overflow: scroll; position:relative; } .tbLock /*设置单元格间隙的样式*/ { border-collapse:collapse; } .lockRowBg { background-color:#CFF; } .lockColumnBg { background-color:#CFF; }</style> </head> <body> <div class="divBoxing" id:="divBoxing" style=" 100%; height: 300px;"> <table width="800" border="0" id="lockTable" class="tbLock"> <tbody> <tr class="LockRow lockRowBg"> <td width="100" align="center" class="LockCell LockCross lockRowBg">第一列</td> <td width="100" align="center" class="LockCell LockCross lockRowBg">第二列</td> <td width="100" align="center">第三列</td> <td width="100" align="center">第四列</td> <td width="100" align="center">第五列</td> <td width="100" align="center">第六列</td> <td width="100" align="center">第七列</td> <td width="100" align="center">第八列</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-2</td> <td align="center" class="LockCell lockColumnBg">2-2</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-3</td> <td align="center" class="LockCell lockColumnBg">2-3</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-4</td> <td align="center" class="LockCell lockColumnBg">2-4</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-5</td> <td align="center" class="LockCell lockColumnBg">2-5</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-6</td> <td align="center" class="LockCell lockColumnBg">2-6</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-7</td> <td align="center" class="LockCell lockColumnBg">2-7</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-8</td> <td align="center" class="LockCell lockColumnBg">2-8</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-9</td> <td align="center" class="LockCell lockColumnBg">2-9</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-10</td> <td align="center" class="LockCell lockColumnBg">2-10</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-11</td> <td align="center" class="LockCell lockColumnBg">2-11</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-12</td> <td align="center" class="LockCell lockColumnBg">2-12</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-13</td> <td align="center" class="LockCell lockColumnBg">2-13</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-14</td> <td align="center" class="LockCell lockColumnBg">2-14</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" class="LockCell lockColumnBg">1-15</td> <td align="center" class="LockCell lockColumnBg">2-15</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> </tbody> </table> </div> </body> </html>
三、使用jQuery开发一个简单的行列锁定插件
如果仅仅从实现上来说,到了第二部我们今天的内容就结束了。但是聪明的读者或许已经发现上面的用法存在的问题:第一我们需要手动的添加很多的class样式、需要对原有布局修改;第二我们上面使用了expression这个IE所特有的样式(虽然我们上面说过这个差距不适用于其他浏览器新版本,但是不代表不适用于旧版本,如果我们修改expression为纯js方式也就可以使用于其他低版本浏览器)。我们刚才说过第二种方式有一个优点就是便于封装而且几乎不必对原table布局作出修改,因此我们不妨对整个应用进行一下简单的封装,使其只需要简单的添加一行js就能够完美的运行。虽然在这个过程中我们只是将手动添加class样式换成动态添加、将expression表达换成onscroll事件,但是一切看起来确实那么的不一样。
下面就是我们使用jQuery进行封装的代码TableLock.js:
/* author:KenshinCui date:2011.03.29 example:$.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,'100%',height:'300px'}); */ (function($) { $.extend($.fn, { TableLock: function(options) { var tl = $.extend({ table:'lockTable',//table的id lockRow:1,//固定行数 lockColumn:1,//固定列数 '100%',//表格显示宽度(实质是外出div宽度) height:'100%',//表格显示高度(实质是外出div高度) lockRowCss:'lockRowBg',//锁定行的样式 lockColumnCss:'lockColumnBg'//锁定列的样式 }, options); var tableId=tl.table; var table=$('#'+tableId); var rowSpan=function(tr){ } if(table){ var box=$("<div id:='divBoxing' class='divBoxing'></div>").scroll(function(){//在此处添加事件 $('.LockRow').css('top',$(this).attr('scrollTop')+'px'); $('.LockCell').css('left',$(this).attr('scrollLeft')+'px'); }); box.css('width',tl.width).css('height',tl.height);//设置高度和宽度 table.wrap(box); table.addClass('tbLock'); var crossNum=tl.lockRow*tl.lockColumn; if(tl.lockRow>0){ var tr; for(var r=0;r<tl.lockRow;++r){//添加行锁定 tr=table.find('tr:eq('+r+')').addClass('LockRow').addClass(tl.lockRowCss); for(var c=0;c<tl.lockColumn;++c){//设置交叉单元格样式,除了锁定单元格外还有交叉单元格自身样式 if(tr) tr.find('td:eq('+c+')').addClass('LockCell LockCross').addClass(tl.lockRowCss); } } } if(tl.lockColumn>0){ var rowNum=$('#'+tableId+' tr').length; var tr; for(var r=(tl.lockRow);r<rowNum;++r){ tr=table.find('tr:eq('+r+')'); for(var c=0;c<tl.lockColumn;++c){//添加列锁定 tr.find('td:eq('+c+')').addClass('LockCell').addClass(tl.lockColumnCss); } } } //box.live('scroll',func); }else{ alert('没有找到对应的table元素,请确保table属性正确性!'); } } }); })(jQuery);
具体的样式表文件TableLock.css:
.LockRow /*固定行的样式*/ { position: relative; /*top: expression(this.parentElement.parentElement.parentElement.scrollTop);*/ top:0px; z-index:2; } .LockCell /*固定列的样式*/ { position: relative; /*left: expression(this.parentElement.parentElement.parentElement.parentElement.scrollLeft);*/ left:0px; z-index:0; } .LockCross /*行列交叉处样式*/ { z-index:3; } .divBoxing /*外出div样式*/ { clear:both; overflow: scroll; position:relative; } .tbLock /*设置单元格间隙的样式*/ { border-collapse:collapse; } .lockRowBg { background-color:#CFF; } .lockColumnBg { background-color:#CFF; }
假设现在你有有这样一个页面,当然它不具备锁定行列的功能:
<!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> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>不具备锁定行列功能的Table</title> </head> <body> <table width="800" border="0"> <tbody> <tr> <td width="100" align="center" >第一列</td> <td width="100" align="center" >第二列</td> <td width="100" align="center">第三列</td> <td width="100" align="center">第四列</td> <td width="100" align="center">第五列</td> <td width="100" align="center">第六列</td> <td width="100" align="center">第七列</td> <td width="100" align="center">第八列</td> </tr> <tr> <td align="center" >1-2</td> <td align="center" >2-2</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-3</td> <td align="center" >2-3</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-4</td> <td align="center" >2-4</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-5</td> <td align="center" >2-5</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-6</td> <td align="center" >2-6</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-7</td> <td align="center" >2-7</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-8</td> <td align="center" >2-8</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-9</td> <td align="center" >2-9</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-10</td> <td align="center" >2-10</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-11</td> <td align="center" >2-11</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-12</td> <td align="center" >2-12</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-13</td> <td align="center" >2-13</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-14</td> <td align="center" >2-14</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center" >1-15</td> <td align="center" >2-15</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> </tbody> </table> </body> </html>
如果你需要让它拥有锁定行列的功能,只需要引入TableLock.js和TableLock.css(当然不要忘了jquery类库),然后添加一句简单的代码即可:
<mce:script type="text/javascript" language="javascript"><!-- $(function(){ $.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,'100%',height:'300px'}); }); // --></mce:script>
下面是完整的页面代码:
<!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> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>TableLock插件演示</title> <link rel="stylesheet" href="TableLock.css" mce_href="TableLock.css" /> <mce:script type="text/javascript" language="javascript" src="jquery-1.5.1.js" mce_src="jquery-1.5.1.js"></mce:script> <mce:script type="text/javascript" language="javascript" src="TableLock.js" mce_src="TableLock.js"></mce:script> <mce:script type="text/javascript" language="javascript"><!-- $(function(){ $.fn.TableLock({table:'lockTable',lockRow:1,lockColumn:2,'100%',height:'300px'}); }); // --></mce:script> </head> <body> <table id="lockTable" width="800" border="0"> <tr> <td width="100" align="center">第一列</td> <td width="100" align="center">第二列</td> <td width="100" align="center">第三列</td> <td width="100" align="center">第四列</td> <td width="100" align="center">第五列</td> <td width="100" align="center">第六列</td> <td width="100" align="center">第七列</td> <td width="100" align="center">第八列</td> </tr> <tr> <td align="center">1-2</td> <td align="center">2-2</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-3</td> <td align="center">2-3</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-4</td> <td align="center">2-4</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-5</td> <td align="center">2-5</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-6</td> <td align="center">2-6</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-7</td> <td align="center">2-7</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-8</td> <td align="center">2-8</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-9</td> <td align="center">2-9</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-10</td> <td align="center">2-10</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-11</td> <td align="center">2-11</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-12</td> <td align="center">2-12</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-13</td> <td align="center">2-13</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-14</td> <td align="center">2-14</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> <tr> <td align="center">1-15</td> <td align="center">2-15</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> <td align="center">--</td> </tr> </table> </body> </html>
下面是运行后的效果:
注意:请确保在IE下.divBoxing具有position:relative;样式,否则在IE6和IE7中锁定行列将会溢出外层div,具体参见IE6 bug with overflow and position:relative 。
本作品采用知识共享署名 2.5 中国大陆许可协议进行许可,欢迎转载,演绎或用于商业目的。但转载请注明来自崔江涛(KenshinCui),并包含相关链接。