HTML+CSS+JS實現完美兼容各大浏覽器的TABLE固定列
本文給大家分享的是使用HTML+CSS+JS實現完美兼容各大浏覽器的TABLE固定列的方法和示例,非常的實用,特別是在BS架構的企業級應用,有需要的小伙伴可以參考下。
BS架構的企業級應用中,當一個表格列數較多時,用戶一個常見的需求就是把前面幾個重要的列固定住,這樣拖動滾動條時固定的列會方便用戶查看數據,用戶體驗很好。一些重量級的JS組件庫也都有這個功能,那麼有沒有更簡單的方法實現這個功能呢?
這個需求常見的解決方案是使用表格拼接的方法,這個方案如果要制作靜態的網頁,或者功能簡單的動態頁面,邏輯比較簡單,技術上也不復雜,很容易實現,但是如果要做成組件,動態功能較多的話,就需要寫大量的冗余代碼,難以維護,甚至於一個簡單的功能,都需要寫很多的代碼,比如事件處理等,這個方法就顯得比較笨拙,靈活性很差,不是一個好的方案。
經過長時間的分析研究,各種場景的試驗,我們找到了一個兼容性非常好的解決方案,總體上來講采用的是定位計算的方法,下面貼出代碼,然後做個解讀。
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 <!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>無標題文檔</title> <script type="text/javascript"> function divScroll(scrollDiv){ var scrollLeft = scrollDiv.scrollLeft; document.getElementById("tableDiv_title").scrollLeft = scrollLeft; document.getElementById("tableDiv_body").scrollLeft = scrollLeft; } function divYScroll(scrollYDiv){ var scrollTop = scrollYDiv.scrollTop; document.getElementById("tableDiv_y").scrollTop = scrollTop; } function onwheel(event){ var evt = event||window.event; var bodyDivY = document.getElementById("tableDiv_y"); var scrollDivY = document.getElementById("scrollDiv_y"); if (bodyDivY.scrollHeight>bodyDivY.offsetHeight){ if (evt.deltaY){ bodyDivY.scrollTop = bodyDivY.scrollTop + evt.deltaY*7; scrollDivY.scrollTop = scrollDivY.scrollTop + evt.deltaY*7; }else{ bodyDivY.scrollTop = bodyDivY.scrollTop - evt.wheelDelta/5; scrollDivY.scrollTop = scrollDivY.scrollTop - evt.wheelDelta/5; } } } </script> <style type="text/css"> body { margin:0; padding:0; } table { border-collapse:collapse; border:0; border:none; } table td { border:1px solid #000; overflow:hidden; padding:0 2px; } </style> </head> <body> <div style="width:500px; position:relative; padding-right:18px;"> <div style="position:relative;height:368px;overflow:hidden;width:100%"> <div style="padding-left:108px; width:auto; overflow:hidden; background:#f00;" id="tableDiv_title" > <table border="0" cellspacing="0" cellpadding="0" > <tr> <td style="min-width:30px; max-width:30px; left:0; top:0; width:30px; overflow:hidden; background-color:#f00;position:absolute;z-index:1;">000</td> <td style="min-width:74px; max-width:74px; left:30px; top:0; width:74px; overflow:hidden; background-color:#f00;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> </table> </div> <div style="overflow:hidden; position:absolute;height:128px; width:100%;" id="tableDiv_y" onmousewheel="onwheel(event);" onwheel="onwheel(event);"> <div style="padding-left:108px; width:auto;overflow:hidden;" id="tableDiv_body"> <table border="0" cellspacing="0" cellpadding="0" > <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">001</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff; position:absolute; z-index:1;">002</td> <td style="min-width:74px; max-width:74px; left:30px; width:74px; overflow:hidden;background-color:#fff; position:absolute; z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">003</td> <td style="min-width:74px; max-width:74px;left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">004</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">005</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">006</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">007</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">008</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">009</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> <tr> <td style="min-width:30px; max-width:30px; left:0; width:30px; overflow:hidden; background-color:#fff;position:absolute;z-index:1;">010</td> <td style="min-width:74px; max-width:74px; left: 30px; width: 74px; overflow:hidden;background-color:#fff;position:absolute;z-index:1;">自動表格</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >56454自動</td> <td style="min-width: 100px; max-width: 100px; width: 100px;" >最後一列</td> </tr> </table> </div> </div> <div style="background-color:#eee;overflow:hidden;top:150px; width:100%; z-index:2;position:absolute;"> <div style="margin-left:108px; width:auto;overflow-x:scroll;overflow-y:hidden;" onscroll='divScroll(this);'> <div style="width:630px; height:1px;"></div> </div> </div> </div> <div id="scrollDiv_y" style="display:block; overflow-x:hidden; overflow-y:scroll; position:absolute; top:22px; right:0px; height:118px; padding-bottom:10px;" onscroll='divYScroll(this);'> <div style="width:1px; height:194px;"></div> </div> </div> </div> </body> </html>一、總體結構:
頁面基本元素為DIV+TABLE,固定的列采用絕對定位的方式固定,每一列都要指定固定寬度,為了解決橫豎滾動條的問題,表頭和表體的外面分別包裹兩層DIV,滾動條采用虛擬的方式,固定在固定位置通過JS控制模擬正常DIV滾動條的效果。
二、定位:
固定的列要絕對定位,通過left屬性控制左側位移,為了保證固定列浮動在上方,設置z-index為1,。為了保證有豎滾動條時的正常顯示,表體的外層DIV為絕對定位,由此導致滾動條也都要絕對定位。還有,表頭和表體以及滾動條的內層DIV通過margin-left屬性控制左側外邊距,把固定列的偏移量空余出來。
二、寬度計算:
每一列的寬度都要指定固定的值,並且要注意一個關鍵點,就是還要加上min-width和max-width屬性,這兩個屬性和width值相等,表頭表體的內層DIV,寬度為auto,自適應表格寬度,外層DIV寬度為100%,最外層的DIV通過padding-right屬性控制右側內邊距,將豎滾動條的位置空余出來。
三、高度計算:
因為絕對定位的存在,整個表格組件的高度要指定,可以通過計算得出,豎滾動條的top值也需要進行計算。
四、滾動條:
本方案一個突出特點,就是虛擬的滾動條,就是通過一個和表格一樣寬、高度為一個像素的DIV模擬出表體DIV的橫向滾動條,豎滾動條同理。之所以采用這個形式,一個是橫向滾動條這樣處理比較美觀,豎滾動條這樣處理之後,表頭和表體的外層DIV寬度不用計算了,都為100%,否則存在滾動條時,表頭和橫向滾動條要空出豎滾動條寬度的位移,否則無法對齊,這個計算倒不復雜,但是某些情況下存在問題,在此不展開了。
五、滾動事件:
因為表體的滾動條都隱藏了,導致鼠標滾輪不起作用了,這樣就需要用JS處理鼠標滾輪事件,本文的樣例代碼兼容常見浏覽器。這裡的重點是同時寫了onmousewheel和onwheel事件,onmousewheel兼容IE,在計算滾動距離時,注意deltaY和wheelDelta屬性的差異即可。
六、優缺點分析:
本文的解決方案已經經過精簡,重點是講清楚原理,在我們的實際中,非常的復雜。這個設計考慮了非常多的兼容性,包括了浏覽器的兼容性和各種場景的兼容性,如果需求簡單,還有簡化的空間。
這個方案的優點是,如果要做組件的話,因為HTML結構簡單,表頭和表體都是一個TABLE,JS控制代碼非常干淨,維護容易。缺點就是計算過多。我們認為該方案比較適用於開發組件的情況,靜態頁面就有點小題大作了。
以上所述就是本文的全部內容了,希望大家能夠喜歡。