JavaScript Table行定位效果

本文介绍了一个使用JavaScript实现的表格行定位效果,该效果允许在滚动长表格时将特定行固定在视口内,以增强用户体验。代码兼容多种浏览器,并提供了自定义定位位置的功能。

这个是静态页面,把下面的全部粘贴到.html页面运行就可以了。里面有很多学习的地方。

在以后的开发过程中可能要用到一些。 

 

<!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=gb2312" />
<title>JavaScript Table行定位效果</title>
<script>
var isIE = (document.all) ? true : false;

var isIE6 = isIE && (navigator.userAgent.indexOf('MSIE 6.0') != -1);
var isIE7 = isIE && (navigator.userAgent.indexOf('MSIE 7.0') != -1);
var isIE6or7 = isIE6 || isIE7;

var isChrome = navigator.userAgent.indexOf('Chrome') != -1;

var $ = function (id) {
 return "string" == typeof id ? document.getElementById(id) : id;
};

var Extend = function(destination, source) {
 for (var property in source) {
  destination[property] = source[property];
 }
 return destination;
}


var CurrentStyle = function(element){
 return element.currentStyle || document.defaultView.getComputedStyle(element, null);
}

var forEach = function(array, callback, thisObject){
 if(array.forEach){
  array.forEach(callback, thisObject);
 }else{
  for (var i = 0, len = array.length; i < len; i++) { callback.call(thisObject, array[i], i, array); }
 }
}

var Filter = function(array, callback, thisObject){
 if(array.filter){
  return array.filter(callback, thisObject);
 }else{
  var res = [];
  for (var i = 0, len = array.length; i < len; i++) { callback.call(thisObject, array[i], i, array) && res.push(array[i]); }
  return res;
 }
}

var Bind = function(object, fun) {
 var args = Array.prototype.slice.call(arguments).slice(2);
 return function() {
  return fun.apply(object, args.concat(Array.prototype.slice.call(arguments)));
 }
}

function addEventHandler(oTarget, sEventType, fnHandler) {
 if (oTarget.addEventListener) {
  oTarget.addEventListener(sEventType, fnHandler, false);
 } else if (oTarget.attachEvent) {
  oTarget.attachEvent("on" + sEventType, fnHandler);
 } else {
  oTarget["on" + sEventType] = fnHandler;
 }
};


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() {
 //用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;
  },
  //设置新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 = [];
  }
};
</script>
</head>
<body style="height:1000px; width:1000px; padding-top:200px;">
<style type="text/css">
.tablefixed{width:600px; border-collapse:collapse;}
.tablefixed td{ border:5px solid #999; padding:10px;}
.tablefixed thead, .tablefixed tfoot{ background:#CCC;}
</style>
<table id="idTableFixed" class="tablefixed">
 <thead>
  <tr>
   <td width="50"></td>
   <td>表头</td>
   <td width="100"></td>
  </tr>
 </thead>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/07/06/1236770.html">图片滑动切换效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/05/23/1205642.html">图片变换效果(ie only)</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/07/21/1247267.html">图片切割效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/09/15/1290954.html">仿LightBox内容显示效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/05/13/1194272.html">图片滑动展示效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/10/20/1314766.html">仿163网盘无刷新文件上传系统</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/11/17/1334778.html">拖放效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/10/05/1303993.html">图片切割系统</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/06/28/1231557.html">自定义多级联动浮动菜单</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/12/24/1360988.html">滑动条效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/12/03/1346386.html">拖拉缩放效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/08/27/1277131.html">渐变效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2008/10/06/1304414.html">Table排序</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2009/01/06/1369979.html">Tween算法及缓动效果</a></td>
  <td></td>
 </tr>
 <tr>
  <td></td>
  <td><a href="http://www.cnblogs.com/cloudgamer/archive/2009/03/11/1408333.html">颜色梯度和渐变效果</a></td>
  <td></td>
 </tr>
 <tfoot>
  <tr>
   <td></td>
   <td>表尾</td>
   <td></td>
  </tr>
 </tfoot>
</table>
<br />
点击行选择克隆行:当前克隆第 <span id="idIndex">1</span> 行<br />
<br />
<input id="idPos" type="button" value="指定中间位置" />
<input id="idHide" type="button" value="取消定位" />
<br />
<br />
ps:为方便预览,建议缩小浏览器。
<script>
var tf = new TableFixed("idTableFixed");

forEach($("idTableFixed").rows, function(o, i){
 var n = i + 1;
 o.cells[0].innerHTML = n;
 o.cells[2].innerHTML = n % 4 ? "&nbsp;" : "<select><option>test</option></select>";
 o.onclick = function(){
  $("idIndex").innerHTML = n; tf.Auto = true; tf.Clone(i);
 }
});

tf.Clone();//表格结构修改后应重新Clone一次

$("idPos").onclick = function(){
 tf.Auto = false; tf.SetPos(.5);
}

$("idHide").onclick = function(){
 if(tf.Hide){
  tf.Hide = false;
  this.value = "取消定位";
 }else{
  tf.Hide = true;
  this.value = "显示定位";
 }
 tf.Run();
}
</script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值