HTML+CSS+JS實現TABLE固定列(常見瀏覽器兼容)的最佳實踐

        BS架構的企業級應用中,當一個表格列數較多時,用戶一個常見的需求就是把前面幾個重要的列固定住,這樣拖動滾動條時固定的列會方便用戶查看數據,用戶體驗很好。一些重量級的JS組件庫也都有這個功能,那麼有沒有更簡單的方法實現這個功能呢?javascript

        這個需求常見的解決方案是使用表格拼接的方法,這個方案若是要製做靜態的網頁,或者功能簡單的動態頁面,邏輯比較簡單,技術上也不復雜,很容易實現,可是若是要作成組件,動態功能較多的話,就須要寫大量的冗餘代碼,難以維護,甚至於一個簡單的功能,都須要寫不少的代碼,好比事件處理等,這個方法就顯得比較笨拙,靈活性不好,不是一個好的方案。
css

        通過長時間的分析研究,各類場景的試驗,咱們找到了一個兼容性很是好的解決方案,整體上來說採用的是定位計算的方法,下面貼出代碼,而後作個解讀。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=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>

    1、整體結構:java

            頁面基本元素爲DIV+TABLE,固定的列採用絕對定位的方式固定,每一列都要指定固定寬度,爲了解決橫豎滾動條的問題,表頭和表體的外面分別包裹兩層DIV,滾動條採用虛擬的方式,固定在固定位置經過JS控制模擬正常DIV滾動條的效果。瀏覽器

    2、定位:架構

            固定的列要絕對定位,經過left屬性控制左側位移,爲了保證固定列浮動在上方,設置z-index爲1,。爲了保證有豎滾動條時的正常顯示,表體的外層DIV爲絕對定位,由此致使滾動條也都要絕對定位。還有,表頭和表體以及滾動條的內層DIV經過margin-left屬性控制左側外邊距,把固定列的偏移量空餘出來。
ui

    2、寬度計算:this

            每一列的寬度都要指定固定的值,而且要注意一個關鍵點,就是還要加上min-width和max-width屬性,這兩個屬性和width值相等,表頭表體的內層DIV,寬度爲auto,自適應表格寬度,外層DIV寬度爲100%,最外層的DIV經過padding-right屬性控制右側內邊距,將豎滾動條的位置空餘出來。
spa

    3、高度計算:設計

            由於絕對定位的存在,整個表格組件的高度要指定,能夠經過計算得出,豎滾動條的top值也須要進行計算。

    4、滾動條:

            本方案一個突出特色,就是虛擬的滾動條,就是經過一個和表格同樣寬、高度爲一個像素的DIV模擬出表體DIV的橫向滾動條,豎滾動條同理。之因此採用這個形式,一個是橫向滾動條這樣處理比較美觀,豎滾動條這樣處理以後,表頭和表體的外層DIV寬度不用計算了,都爲100%,不然存在滾動條時,表頭和橫向滾動條要空出豎滾動條寬度的位移,不然沒法對齊,這個計算倒不復雜,可是某些狀況下存在問題,在此不展開了。

    5、滾動事件:

            由於表體的滾動條都隱藏了,致使鼠標滾輪不起做用了,這樣就須要用JS處理鼠標滾輪事件,本文的樣例代碼兼容常見瀏覽器。這裏的重點是同時寫了onmousewheel和onwheel事件,onmousewheel兼容IE,在計算滾動距離時,注意deltaY和wheelDelta屬性的差別便可。

    6、優缺點分析:

            本文的解決方案已經通過精簡,重點是講清楚原理,在咱們的實際中,很是的複雜。這個設計考慮了很是多的兼容性,包括了瀏覽器的兼容性和各類場景的兼容性,若是需求簡單,還有簡化的空間。

            這個方案的優勢是,若是要作組件的話,由於HTML結構簡單,表頭和表體都是一個TABLE,JS控制代碼很是乾淨,維護容易。缺點就是計算過多。咱們認爲該方案比較適用於開發組件的狀況,靜態頁面就有點小題大做了。

相關文章
相關標籤/搜索