对于table的一些基础信息不了解的,可以参考我以前写过的一篇《关于table的一些记录》。下面演示的代码,具体的源码可以参考此处。
一、表格固定左边与顶部
公司最近要做个排期系统,当滚动表格的时候,需要将顶部和左边的分别固定起来。
1)固定顶部
原理就是用标签模拟出顶部的样式,通过脚本计算出高度,以及各个块的宽度,再将table中的thead的内容覆盖掉。
1. 样式:通过绝对定位,将ul中的内容覆盖中顶部。
<ul class="calendar-table-top-header"> <li></li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> <li>7</li> <li>8</li> <li>9</li> <li>10</li> <li>11</li> <li>12</li> <li>13</li> </ul>
2. 计算尺寸:通过获取到th标签的宽和高,赋给对应的li标签。涉及到了元素的offsetHeight、offsetWidth属性,更多关于尺寸的信息可以参考《JavaScript中尺寸、坐标》
function fixedTopHeader($table) { $table.siblings('.calendar-table-top-header').remove();//移除原先的模拟顶部 var $ul = $('<ul>').addClass('calendar-table-top-header'), $ths = $table.find('thead th'); $ul.width($table.find('thead')[0].offsetWidth + 1); $.each($ths, function(key, value) {//遍历th标签,设置li的宽高 var $th = $(value); var $child = $('<li>').css({ height: $th[0].offsetHeight, width: $th[0].offsetWidth }).html($th.html()); $ul.append($child); }); $table.before($ul); }
2)固定左边
固定左边与固定顶部的原理是一样的,代码也很类似。
1. 节流:创建元素的代码已经实现,接下来要实现执行上述代码的事件“scroll”,这里涉及到一个节流的概念,节流是一种代码优化。
如果不做节流,那么将会损耗性能,导致在滚定的时候,展示的固定元素一卡一卡的,很不流畅,在《JavaScript优化以及开发小技巧》中曾经解释过节流的概念。
二、表格中嵌套表格
嵌套的表格每一行的高度要与外面的表格一致,并且最后一行需要将滚动条的高度去除,否则会影响整个高度的展示。
1. 头部元素:头部“2016年11月”,如果用跨列colspan来做的话,每次都要计算列的个数,所以这里用了“caption”标签,不过在上下对齐方面没有th标签方便。
<table class="table table-bordered"> <caption>2016年11月</caption> <tbody> <tr>...</tr> </tbody> </table>
2. tr高度:这里的tr获取的是外面的table,不是嵌套的table。tr的高度有两个比较特殊,第一个和最后一个,分别要减去1和18,上边框与滚动条的高度。
$schedule.children('tbody').children('tr').each(function() { heights.push(this.getBoundingClientRect().height); }); if (heights.length == 0) return; heights[0] -= 1; //去除下边框 heights[heights.length - 1] -= 18;//去除滚动条的高度
3. 尺寸赋值:分别计算嵌套表格的宽度,算出总宽度,给包裹的div赋总宽度,再给嵌套表格的每个tr赋值。给包裹的div赋了个默认值“width: 2000px;”。
<div class="schedule-hidden"> <div class="day-table" style="width: 2000px;"> <table class="table table-bordered"> <caption>2016年11月</caption> <tbody> <tr>...</tr> </tbody> </table> <table class="table table-bordered"> <caption>2016年12月</caption> <tbody> <tr>...</tr> </tbody> </table> </div> </div>
用的jQuery踩到了一个“height()”方法的小坑。
$tables.each(function() { var $this = $(this); width += this.offsetWidth; $this.children('caption').css('height', heights[0]); //如果用height 会将padding也算在内 $this.find('tr').each(function(index) { $(this).height(heights[index + 1]); }); }); $dayContainer.find('.day-table').width(width);//嵌套表格的外包裹div的宽度,宽度小的话会让表格换行
4. 初始化隐藏:上面HTML代码中用到了“schedule-hidden”,做初始化隐藏,就会向下图那样,拉伸,影响体验。
但是如果用普通的“display:none”做隐藏,就会出现包裹的div宽度“width:0”,这是因为“none”内的元素没有物理尺寸,占据的空间位置不存在。
.table-schedule .schedule-hidden { display: none; }
所以就用变通的方法,“height:0”来做隐藏。或者用“position和left”组合,或用“visibility”,或者用“opacity”。
.table-schedule .schedule-hidden { height: 0; /*position: absolute; left:-10000px;*/ /*opacity: 0;*/ /*visibility: hidden;*/ }