對於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;*/ }