【问题标题】:How can I lock the first row and first column of a table when scrolling, possibly using JavaScript and CSS?滚动时如何锁定表格的第一行和第一列,可能使用 JavaScript 和 CSS?
【发布时间】:2010-09-22 16:48:30
【问题描述】:

当您激活“冻结窗格”时,如何创建一个表,它的第一行和第一列都被锁定,就像在 Excel 中一样?我需要表格水平和垂直滚动(存在很多解决方案,但只允许垂直滚动)。

因此,当您在表格中向下滚动时,第一行将保持不变,因为它将包含列标题。这最终可能会出现在 thead 中,也可能不会出现,这会使解决方案更容易。

当您向右滚动时,第一列保持不变,因为它包含行的标签。

我很确定这仅靠 CSS 是不可能的,但是谁能指出我的 JavaScript 解决方案?它需要在所有主流浏览器中运行。

【问题讨论】:

  • 嗨,我知道这有点老了,但是你有解决这个问题的方法吗?标记为正确的答案现在已断开链接。我试图在这里找到同样的事情:stackoverflow.com/questions/743663/…
  • 我刚刚尝试了接受答案中的链接,它们对我有用。你还在烦恼吗?

标签: javascript css excel scroll css-tables


【解决方案1】:

它实际上在没有 JavaScript 的情况下是可行的,但是使用带有粘性位置的纯 CSS + HTML。只需将“position:sticky”添加到您要冻结的单元格中即可。

对于构建表格,您可以使用 CSS 网格或 CSS 网格,此技术适用于两者。

这是一个带有表格标签 (live demo here) 的示例格式:

<table>
  <tr><th class="head"></th class="head"><th></th> ... </tr>
  <tr><th class="head"></th>             <th></th> ... </tr>
...
</table>
<style type="text/css">
  .head { position: sticky; top: 0; left: 0;}
</style>

这里有一个 CSS Grid 示例 (live demo here):

<div class="grid">
   <!-- cells to freeze -->
   <div class="entry head"></div>
   <div class="entry head"></div>
   ...
   <!-- normal cells -->
   <div class="entry"></div>
   ...
</div>
<style type="text/css">
  .grid {
    display: grid;
    grid-template-columns: repeat(<your-cell-count>, <cell-size>); 
  } 
  .entry.head { position: sticky; top: 0; left: 0 }
</style>

您可能需要处理水平和垂直冻结的单元格(例如,设置比其他更大的 z-index),但这仍然是 CSS 的事情。

我认为这种方法的主要缺点可能是浏览器兼容性问题。在使用这些技术之前检查Can I Use CSS-stickyCan I use CSS grid

【讨论】:

    【解决方案2】:

    这是我制作的纯 javascript/css。

    https://jsfiddle.net/KirbyLWallace/x5sbe0dk/5/

    它本应用于全宽屏幕,但我已经修改为适合小提琴的特定宽度。

    <body onResize="scaleElements()">
    
    <div id="table-container-div">
    
    <table id="data-table">
      <thead id="th-header">
        <tr id="th-header-row">
          <td>Column1</td>
          <td>Column2</td>
          <td>Column3</td>
          <td>Column4</td>
        </tr>
      </thead>
    
      <tbody id="tbl-body">
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
        <tr><td>a</td><td>b</td><td>c</td><td>d</td></tr>
        <tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
        <tr><td>h</td><td>i</td><td>j</td><td>k</td></tr>
      </tbody>
    
    </table>
    

    javascript:

    (() => {
            scaleElements();  
        })();
    
    
      function scaleElements() {
    
            // element() is just shorthand for document.getElementById().
    
            // scaleElements() scales a number of other things, not included here, 
            // that get rescaled any time the browser, or a container is resized.
            // the table header row here is just one of them...
            //
            // this thing includes checks to see if a table with the table & thead 
            // is on the page.  If it is, it checks to see if the span container is
            // here (it's not on the first run, but it is on subsequent calls.  So, 
            // it adds it if it needs it, or reuses it if it's there.
    
            if (element("data-table")) {
    
                if (element("th-span-container")) {
                    element("th-span-container").parentElement.removeChild(element("th-span-container"));
                }
    
                var x = document.createElement("div");
                    x.id = "th-span-container";
                    x.style.cssFloat = "left";
                    x.style.position = "fixed";
                    x.style.top = "10px";
    
                    // you will want to fiddle with your own particular positioning. 
                    // this one is positioned to work on a table that is below a page 
                    // logo banner.
    
                var tds = element("th-header-row").getElementsByTagName("td");
    
                for (i = 0; i < tds.length; i++) {
    
                    let z = tds[i];
                    let y = document.createElement("span");
    
                    y.style.padding = "0px";
                    y.style.margin = "0px";
                    y.style.fontFamily = "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif";
                    y.style.fontSize = "13px";
                    y.style.border = "0px";
                    y.style.position = "absolute";
                    y.style.color = "white";
                    y.style.backgroundColor = "#3D6588";
                    y.style.left = z.offsetLeft + "px";
                    y.style.height = z.offsetHeight + "px";
                    y.style.lineHeight = z.offsetHeight + "px";
                    y.style.width = z.offsetWidth + "px";
                    y.innerHTML = z.innerHTML;
                    x.appendChild(y);
    
                }
    
                element("table-container-div").appendChild(x);
                element("th-header-row").style.visibility = "hidden";
    
            }
    
        }
    
    function element(e) {
        return document.getElementById(e);
    }
    

    css:

    body {
      background: black;
    }
    
    #table-container-div {
                width: 310px;
                position: absolute;
                top: 10px;
                bottom: 10px;
                overflow-x: hidden;
                overflow-y: auto;
                min-width: 320px;
            }
    
            table {
                font-size: 13px;
                height: 120px;
                width: 300px;
                border: 0px solid red;
                background-color: #11171F;
            }
    
            tr {
                height: 22px;
                color: #cff3ff;
            }
    
                tr:hover {
                    background-color: dimgrey;
                }
    
            td {
              color:white;
                border-right: 1px dotted #4F4F4F;
            }
    
            #th-header-row {
                background-color: #3D6588;
                color: white;
            }
    

    【讨论】:

      【解决方案3】:

      我通过以下组合做到了这一点:

      • 使用多个表
      • 固定大小的单元格
      • jQuery 的 scrollTop 和 scrollLeft 函数

      这里有一个jsfiddle example 来演示。

      尚未在所有浏览器上进行测试,但我认为它在旧 IE 版本上不是很好。

      $("#clscroll-content").scroll(function() {
          $("#clscroll-row-headers").scrollTop($("#clscroll-content").scrollTop());
          $("#clscroll-column-headers").scrollLeft($("#clscroll-content").scrollLeft());
      });
      
      $("#clscroll-column-headers").scroll(function() {
          $("#clscroll-content").scrollLeft($("#clscroll-column-headers").scrollLeft());
      });
      
      $("#clscroll-row-headers").scroll(function() {
          $("#clscroll-content").scrollTop($("#clscroll-row-headers").scrollTop());
      });
      .clscroll table {
          table-layout: fixed;
      }
      
      .clscroll td, .clscroll th { 
          overflow: hidden;
      }
      
      .corner-header {
          float: left;
      }
      
      .column-headers {
          float: left;
          overflow: scroll;
      }
      
      .row-headers {
          clear: both;
          float: left;    
          overflow: scroll;
      }
      
      .table-content {
          table-layout: fixed;
          float: left;
          overflow: scroll;
      }
      
      .clscroll td, .clscroll th { 
          width: 200px;
          border: 1px solid black;
      }
      
      .row-headers, .table-content {
          height: 100px;
      }
      
      .column-headers, .table-content, .table-content table, .column-headers table {
          width: 400px;
      }
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <div class="clscroll corner-header">
        <table>
            <tr>
                <th>&nbsp;</th>
            </tr>
        </table>
      </div>
      <div class="clscroll column-headers" id="clscroll-column-headers">
        <table>
            <tr>
                <th>Bus</th>
                <th>Plane</th>
                <th>Boat</th>
                <th>Bicycle</th>
            </tr>
        </table>
      </div>
      <div class="clscroll row-headers" id="clscroll-row-headers">
        <table>
            <tr>
                <th>Red</th>
            </tr>
            <tr>
                <th>Green</th>
            </tr>
            <tr>
                <th>Blue</th>
            </tr>
            <tr>
                <th>Orange</th>
            </tr>
            <tr>
                <th>Purple</th>
            </tr>
            <tr>
                <th>Yellow</th>
            </tr>
            <tr>
                <th>Pink</th>
            </tr>
            <tr>
                <th>Brown</th>
            </tr>
        </table>
      </div>
      <div class="clscroll table-content" id="clscroll-content">
        <table>
            <tr>
                <td>Red Bus</td>
                <td>Red Plane</td>
                <td>Red Boat</td>
                <td>Red Bicycle</td>
            </tr>
            <tr>
                <td>Green Bus</td>
                <td>Green Plane</td>
                <td>Green Boat</td>
                <td>Green Bicycle</td>
            </tr>
            <tr>
                <td>Blue Bus</td>
                <td>Blue Plane</td>
                <td>Blue Boat</td>
                <td>Blue Bicycle</td>
            </tr>
            <tr>
                <td>Orange Bus</td>
                <td>Orange Plane</td>
                <td>Orange Boat</td>
                <td>Orange Bicycle</td>
            </tr>
            <tr>
                <td>Purple Bus</td>
                <td>Purple Plane</td>
                <td>Purple Boat</td>
                <td>Purple Bicycle</td>
            </tr>
            <tr>
                <td>Yellow Bus</td>
                <td>Yellow Plane</td>
                <td>Yellow Boat</td>
                <td>Yellow Bicycle</td>
            </tr>
            <tr>
                <td>Pink Bus</td>
                <td>Pink Plane</td>
                <td>Pink Boat</td>
                <td>Pink Bicycle</td>
            </tr>
            <tr>
                <td>Brown Bus</td>
                <td>Brown Plane</td>
                <td>Brown Boat</td>
                <td>Brown Bicycle</td>
            </tr>
        </table>
      </div>

      【讨论】:

      【解决方案4】:

      Sort and Lock Table 是我见过的唯一可以在 IE 以外的其他浏览器上运行的解决方案。 (尽管这个 "locked column css" 也可以解决问题)。下面是必需的代码块。

      <!DOCTYPE html>
      <html>
      <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <meta name="robots" content="noindex, nofollow">
        <meta name="googlebot" content="noindex, nofollow">
        <script type="text/javascript" src="/js/lib/dummy.js"></script>
          <link rel="stylesheet" type="text/css" href="/css/result-light.css">
        <style type="text/css">
          /* Scrollable Content Height */
      .scrollContent {
       height:100px;
       overflow-x:hidden;
       overflow-y:auto;
      }
      .scrollContent tr {
       height: auto;
       white-space: nowrap;
      }
      
      /* Prevent Mozilla scrollbar from hiding right-most cell content */
      .scrollContent tr td:last-child {
       padding-right: 20px;
      }
      
      /* Fixed Header Height */
      .fixedHeader tr {
       position: relative;
       height: auto;
      }
      
      /* Put border around entire table */
      div.TableContainer {
       border: 1px solid #7DA87D;
      }
      
      /* Table Header formatting */
      .headerFormat {
       background-color: white;
       color: #FFFFFF;
       margin: 3px;
       padding: 1px;
       white-space: nowrap;
       font-family: Helvetica;
       font-size: 16px;
       text-decoration: none;
       font-weight: bold;
      }
      .headerFormat tr td {
       border: 1px solid #000000;
       background-color: #7DA87D;
      }
      
      /* Table Body (Scrollable Content) formatting */
      .bodyFormat tr td {
          color: #000000;
          margin: 3px;
          padding: 1px;
          border: 0px none;
          font-family: Helvetica;
          font-size: 12px;
      }
      
      /* Use to set different color for alternating rows */
      .alternateRow {
        background-color: #E0F1E0;
      }
      
      /* Styles used for SORTING */
      .point {
       cursor:pointer;
      }
      td.sortedColumn {
        background-color: #E0F1E0;
      }
      
      tr.alternateRow td.sortedColumn {
        background-color: #c5e5c5;
      }
      .total {
          background-color: #FED362;
          color: #000000;
          white-space: nowrap;
          font-size: 12px;
          text-decoration: none;
      }
        </style>
      
        <title></title>
      <script type='text/javascript'>//<![CDATA[
      
      /* This script and many more are available free online at
      The JavaScript Source :: http://www.javascriptsource.com
      Created by: Stan Slaughter :: http://www.stansight.com/ */
      
      /* ======================================================
      Generic Table Sort
      
      Basic Concept: A table can be sorted by clicking on the title of any
      column in the table, toggling between ascending and descending sorts.
      
      
      Assumptions:
      
      * The first row of the table contains column titles that are "clicked"
        to sort the table
      
      * The images 'desc.gif','asc.gif','none.gif','sorting.gif' exist
      
      * The img tag is in each column of the the title row to represent the
        sort graphic.
      
      * The CSS classes 'alternateRow' and 'sortedColumn' exist so we can
        have alternating colors for each row and a highlight the sorted
        column.  Something like the <style> definition below, but with the
        background colors set to whatever you want.
      
         <style>
         tr.alternateRow {
           background-color: #E0F1E0;
         }
      
         td.sortedColumn {
           background-color: #E0F1E0;
         }
      
         tr.alternateRow td.sortedColumn {
           background-color: #c5e5c5;
         }
         </style>
      
      ====================================================== */
      
      function sortTable(td_element,ignoreLastLines) {
      
        // If the optional ignoreLastLines parameter (number of lines *not* to sort at end of table)
        // was not passed then make it 0
        ignoreLastLines = (typeof(ignoreLastLines)=='undefined') ? 0 : ignoreLastLines;
      
        var sortImages =['data:image/gif;base64,R0lGODlhCgAKAMQXAJOkk3mReXume3uTe3mieXGPcXOYc/Hx8Xadds/Wz9vg24ejh3GUcYOgg6a0pnGVcfP18+3w7c3TzdPY06u4q/r8+v///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABcALAAAAAAKAAoAAAUz4IVcZDleixQIQjA1pFFZx2FVRklZvOWUl8LsVgBeFLyE8TLgDZYESISwvAAA1QvjAQwBADs=','data:image/gif;base64,R0lGODlhCgAKAMQXAJOkk3mReXume3uTe3mieXGPcXOYc/Hx8Xadds/Wz9vg24ejh3GUcYOgg6a0pnGVcfP18+3w7c3TzdPY06u4q/r8+v///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABcALAAAAAAKAAoAAAUw4CVeDzOeFwCgIhFBBDtY1sAmtIIWFV0VJweNRhkZeoeDpWIQNSYBgSAgWYgQLGwIADs=','data:image/gif;base64,R0lGODlhCgAKALMLAHaRdnCTcHegd7C8sNTa1Ku4q9vg24GXgfr8+uDl4P///////wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAKAAoAAAQfcMlJq12hIHKoSEqIdBIQnslknkoqfedIBQNikFduRQA7','http://web.archive.org/web/20150906203819im_/http://www.javascriptsource.com/miscellaneous/sorting.gif'];
      
        // Get the image used in the first row of the current column
        var sortColImage = td_element.getElementsByTagName('img')[0];
      
        // If current image is 'asc.gif' or 'none.gif' (elements 1 and 2 of sortImages array) then this will
        // be a descending sort else it will be ascending - get new sort image icon and set sort order flag
        var sortAscending = false;
        var newSortColImage = "";
        if (sortColImage.getAttribute('src').indexOf(sortImages[1])>-1 ||
          sortColImage.getAttribute('src').indexOf(sortImages[2])>-1) {
          newSortColImage = sortImages[0];
          sortAscending = false;
        } else {
          newSortColImage = sortImages[1];
          sortAscending = true;
        }
      
        // Assign "SORTING" image icon (element 3 of sortImages array)) to current column title
        // (will replace with newSortColImage when sort completes)
        sortColImage.setAttribute('src',sortImages[3]);
      
        // Find which column was clicked by getting it's column position
        var indexCol = td_element.cellIndex;
      
        // Get the table element from the td element that was passed as a parameter to this function
        var table_element = td_element.parentNode;
        while (table_element.nodeName != "TABLE") {
          table_element = table_element.parentNode;
        }
      
        // Get all "tr" elements from the table and assign then to the Array "tr_elements"
        var tr_elements = table_element.getElementsByTagName('tr');
      
        // Get all the images used in the first row then set them to 'none.gif'
        // (element 2 or sortImages array) except for the current column (all ready been changed)
        var allImg = tr_elements[0].getElementsByTagName('img');
          for(var i=0;i<allImg.length;i++){
          if(allImg[i]!=sortColImage){allImg[i].setAttribute('src',sortImages[2])}
        }
      
        // Some explantion of the basic concept of the following code before we
        // actually start.  Essentially we are going to copy the current columns information
        // into an array to be sorted. We'll sort the column array then go back and use the information
        // we saved about the original row positions to re-order the entire table.
        // We are never really sorting more than a columns worth of data, which should keep the sorting fast.
      
        // Create a new array for holding row information
        var clonedRows = new Array()
      
        // Create a new array to store just the selected column values, not the whole row
        var originalCol = new Array();
      
        // Now loop through all the data row elements
        // NOTE: Starting at row 1 because row 0 contains the column titles
        for (var i=1; i<tr_elements.length - ignoreLastLines; i++) {
      
         // "Clone" the tr element i.e. save a copy all of its attributes and values
         clonedRows[i]=tr_elements[i].cloneNode(true);
      
         // Text value of the selected column on this row
         var valueCol = getTextValue(tr_elements[i].cells[indexCol]);
      
         // Format text value for sorting depending on its type, ie Date, Currency, number, etc..
         valueCol = FormatForType(valueCol);
      
         // Assign the column value AND the row number it was originally on in the table
         originalCol[i]=[valueCol,tr_elements[i].rowIndex];
        }
      
        // Get rid of element "0" from this array.  A value was never assigned to it because the first row
        // in the table just contained the column titles, which we did not bother to assign.
        originalCol.shift();
      
        // Sort the column array returning the value of a sort into a new array
        sortCol = originalCol.sort(sortCompare);
      
        // If it was supposed to be an Ascending sort then reverse the order
        if (sortAscending) { sortCol.reverse(); }
      
        // Now take the values from the sorted column array and use that information to re-arrange
        // the order of the tr_elements in the table
        for (var i=1; i < tr_elements.length - ignoreLastLines; i++) {
      
          var old_row = sortCol[i-1][1];
          var new_row = i;
          tr_elements[i].parentNode.replaceChild(clonedRows[old_row],tr_elements[new_row]);
        }
      
         // Format the table, making the rows alternating colors and highlight the sorted column
         makePretty(table_element,indexCol,ignoreLastLines);
      
        // Assign correct sort image icon to current column title
        sortColImage.setAttribute('src',newSortColImage);
      }
      
      // Function used by the sort routine to compare the current value in the array with the next one
      function sortCompare (currValue, nextValue) {
       // Since the elements of this array are actually arrays themselves, just sort
       // on the first element which contiains the value, not the second which contains
       // the original row position
        if ( currValue[0] == nextValue[0] ) return 0;
        if ( currValue[0] < nextValue[0] ) return -1;
        if ( currValue[0] > nextValue[0] ) return 1;
      }
      
      //-----------------------------------------------------------------------------
      // Functions to get and compare values during a sort.
      //-----------------------------------------------------------------------------
      
      // This code is necessary for browsers that don't reflect the DOM constants
      // (like IE).
      if (document.ELEMENT_NODE == null) {
         document.ELEMENT_NODE = 1;
         document.TEXT_NODE = 3;
      }
      
      function getTextValue(el) {
        var i;
        var s;
        // Find and concatenate the values of all text nodes contained within the
        // element.
        s = "";
        for (i = 0; i < el.childNodes.length; i++)
          if (el.childNodes[i].nodeType == document.TEXT_NODE)
            s += el.childNodes[i].nodeValue;
          else if (el.childNodes[i].nodeType == document.ELEMENT_NODE &&
                   el.childNodes[i].tagName == "BR")
            s += " ";
          else
            // Use recursion to get text within sub-elements.
            s += getTextValue(el.childNodes[i]);
      
        return normalizeString(s);
      }
      
      // Regular expressions for normalizing white space.
      var whtSpEnds = new RegExp("^\\s*|\\s*$", "g");
      var whtSpMult = new RegExp("\\s\\s+", "g");
      
      function normalizeString(s) {
        s = s.replace(whtSpMult, " ");  // Collapse any multiple whites space.
        s = s.replace(whtSpEnds, "");   // Remove leading or trailing white space.
        return s;
      }
      
      // Function used to modify values to make then sortable depending on the type of information
      function FormatForType(itm) {
        var sortValue = itm.toLowerCase();
      
        // If the item matches a date pattern (MM/DD/YYYY or MM/DD/YY or M/DD/YYYY)
        if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/) ||
            itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/) ||
            itm.match(/^\d[\/-]\d\d[\/-]\d\d\d\d$/) ) {
      
          // Convert date to YYYYMMDD format for sort comparison purposes
          // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
          var yr = -1;
      
          if (itm.length == 10) {
            sortValue = itm.substr(6,4)+itm.substr(0,2)+itm.substr(3,2);
           } else if (itm.length == 9) {
            sortValue = itm.substr(5,4)+"0" + itm.substr(0,1)+itm.substr(2,2);
          } else {
            yr = itm.substr(6,2);
            if (parseInt(yr) < 50) {
              yr = '20'+yr;
            } else {
              yr = '19'+yr;
            }
              sortValue = yr+itm.substr(3,2)+itm.substr(0,2);
          }
      
        }
      
      
      
        // If the item matches a Percent patten (contains a percent sign)
        if (itm.match(/%/)) {
         // Replace anything that is not part of a number (decimal pt, neg sign, or 0 through 9) with an empty string.
         sortValue = itm.replace(/[^0-9.-]/g,'');
         sortValue = parseFloat(sortValue);
        }
      
        // If item starts with a "(" and ends with a ")" then remove them and put a negative sign in front
        if (itm.substr(0,1) == "(" & itm.substr(itm.length - 1,1) == ")") {
         itm = "-" + itm.substr(1,itm.length - 2);
        }
      
      // If the item matches a currency pattern (starts with a dollar or negative dollar sign)
        if (itm.match(/^[£$]|(^-)/)) {
         // Replace anything that is not part of a number (decimal pt, neg sign, or 0 through 9) with an empty string.
         sortValue = itm.replace(/[^0-9.-]/g,'');
         if (isNaN(sortValue)) {
           sortValue = 0;
         } else {
           sortValue = parseFloat(sortValue);
         }
      }
      
        // If the item matches a numeric pattern
        if (itm.match(/(\d*,\d*$)|(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/)) {
         // Replace anything that is not part of a number (decimal pt, neg sign, or 0 through 9) with an empty string.
         sortValue = itm.replace(/[^0-9.-]/g,'');
       //  sortValue = sortValue.replace(/,/g,'');
         if (isNaN(sortValue)) {
           sortValue = 0;
         } else {
           sortValue = parseFloat(sortValue);
         }
        }
      
        return sortValue;
      }
      
      //-----------------------------------------------------------------------------
      // Functions to update the table appearance after a sort.
      //-----------------------------------------------------------------------------
      
      // Style class names.
      var rowClsNm = "alternateRow";
      var colClsNm = "sortedColumn";
      
      // Regular expressions for setting class names.
      var rowTest = new RegExp(rowClsNm, "gi");
      var colTest = new RegExp(colClsNm, "gi");
      
      function makePretty(tblEl, col, ignoreLastLines) {
      
        var i, j;
        var rowEl, cellEl;
      
        // Set style classes on each row to alternate their appearance.
        for (i = 1; i < tblEl.rows.length - ignoreLastLines; i++) {
         rowEl = tblEl.rows[i];
         rowEl.className = rowEl.className.replace(rowTest, "");
          if (i % 2 != 0)
            rowEl.className += " " + rowClsNm;
          rowEl.className = normalizeString(rowEl.className);
          // Set style classes on each column (other than the name column) to
          // highlight the one that was sorted.
          for (j = 0; j < tblEl.rows[i].cells.length; j++) {
            cellEl = rowEl.cells[j];
            cellEl.className = cellEl.className.replace(colTest, "");
            if (j == col)
              cellEl.className += " " + colClsNm;
            cellEl.className = normalizeString(cellEl.className);
          }
        }
      
      
      }
      
      // END Generic Table sort.
      
      // =================================================
      
      // Function to scroll to top before sorting to fix an IE bug
      // Which repositions the header off the top of the screen
      // if you try to sort while scrolled to bottom.
      function GoTop() {
       document.getElementById('TableContainer').scrollTop = 0;
      }
      
      //]]> 
      </script>
      </head>
      <body>
        <table cellpadding="0" cellspacing="0" border="0">
      <tr><td>
      <div id="TableContainer" class="TableContainer" style="height:230px;">
      <table class="scrollTable">
       <thead class="fixedHeader headerFormat">
        <tr>
         <td class="point" onclick="GoTop(); sortTable(this,1);" title="Sort"><b>NAME</b> <img src="data:image/gif;base64,R0lGODlhCgAKALMLAHaRdnCTcHegd7C8sNTa1Ku4q9vg24GXgfr8+uDl4P///////wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAKAAoAAAQfcMlJq12hIHKoSEqIdBIQnslknkoqfedIBQNikFduRQA7" border="0"></td>
         <td class="point" onclick="GoTop(); sortTable(this,1);" title="Sort" align="right"><b>Amt</b> <img src="data:image/gif;base64,R0lGODlhCgAKALMLAHaRdnCTcHegd7C8sNTa1Ku4q9vg24GXgfr8+uDl4P///////wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAKAAoAAAQfcMlJq12hIHKoSEqIdBIQnslknkoqfedIBQNikFduRQA7" border="0"></td>
         <td class="point" onclick="GoTop(); sortTable(this,1);" title="Sort" align="right"><b>Lvl</b> <img src="data:image/gif;base64,R0lGODlhCgAKALMLAHaRdnCTcHegd7C8sNTa1Ku4q9vg24GXgfr8+uDl4P///////wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAKAAoAAAQfcMlJq12hIHKoSEqIdBIQnslknkoqfedIBQNikFduRQA7" border="0"></td>
         <td class="point" onclick="GoTop(); sortTable(this,1);" title="Sort" align="right"><b>Rank</b> <img src="data:image/gif;base64,R0lGODlhCgAKALMLAHaRdnCTcHegd7C8sNTa1Ku4q9vg24GXgfr8+uDl4P///////wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAKAAoAAAQfcMlJq12hIHKoSEqIdBIQnslknkoqfedIBQNikFduRQA7" border="0"></td>
         <td class="point" onclick="GoTop(); sortTable(this,1);" title="Sort" align="right"><b>Position</b> <img src="data:image/gif;base64,R0lGODlhCgAKALMLAHaRdnCTcHegd7C8sNTa1Ku4q9vg24GXgfr8+uDl4P///////wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAKAAoAAAQfcMlJq12hIHKoSEqIdBIQnslknkoqfedIBQNikFduRQA7" border="0"></td>
         <td class="point" onclick="GoTop(); sortTable(this,1);" title="Sort" align="right"><b>Date</b> <img src="data:image/gif;base64,R0lGODlhCgAKALMLAHaRdnCTcHegd7C8sNTa1Ku4q9vg24GXgfr8+uDl4P///////wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAAKAAoAAAQfcMlJq12hIHKoSEqIdBIQnslknkoqfedIBQNikFduRQA7" border="0"></td>
        </tr>
       </thead>
       <tbody class="scrollContent bodyFormat" style="height:200px;">
         <tr class="alternateRow">
          <td>Maha</td>
          <td align="right">$19,923.19</td>
          <td align="right">100</td>
          <td align="right">100</td>
          <td>Owner</td>
          <td align="right">01/02/2001</td>
         </tr>
         <tr>
          <td>Thrawl</td>
          <td align="right">$9,550</td>
          <td align="right">159</td>
          <td align="right">100%</td>
          <td>Co-Owner</td>
          <td align="right">11/07/2003</td>
         </tr>
         <tr class="alternateRow">
          <td>Marhanen</td>
          <td align="right">$223.04</td>
          <td align="right">83</td>
          <td align="right">99%</td>
          <td>Banker</td>
          <td align="right">06/27/2006</td>
         </tr>
         <tr>
          <td>Peter</td>
          <td align="right">$121</td>
          <td align="right">567</td>
          <td align="right">23423%</td>
          <td>FishHead</td>
          <td align="right">06/06/2006</td>
         </tr>
         <tr class="alternateRow">
          <td>Jones</td>
          <td align="right">$15</td>
          <td align="right">11</td>
          <td align="right">15%</td>
          <td>Bubba</td>
          <td align="right">10/27/2005</td>
         </tr>
         <tr>
          <td>Supa-De-Dupa</td>
          <td align="right">$145</td>
          <td align="right">91</td>
          <td align="right">32%</td>
          <td>momma</td>
          <td align="right">12/15/1996</td>
         </tr>
         <tr class="alternateRow">
          <td>ClickClock</td>
          <td align="right">$1,213</td>
          <td align="right">23</td>
          <td align="right">1%</td>
          <td>Dada</td>
          <td align="right">1/30/1998</td>
         </tr>
         <tr>
          <td>Mrs. Robinson</td>
          <td align="right">$99</td>
          <td align="right">99</td>
          <td align="right">99%</td>
          <td>Wife</td>
          <td align="right">07/04/1963</td>
         </tr>
         <tr class="alternateRow">
          <td>Maha</td>
          <td align="right">$19,923.19</td>
          <td align="right">100</td>
          <td align="right">100%</td>
          <td>Owner</td>
          <td align="right">01/02/2001</td>
         </tr>
         <tr>
          <td>Thrawl</td>
          <td align="right">$9,550</td>
          <td align="right">159</td>
          <td align="right">100%</td>
          <td>Co-Owner</td>
          <td align="right">11/07/2003</td>
         </tr>
         <tr class="alternateRow">
          <td>Marhanen</td>
          <td align="right">$223.04</td>
          <td align="right">83</td>
          <td align="right">59%</td>
          <td>Banker</td>
          <td align="right">06/27/2006</td>
         </tr>
         <tr>
          <td>Peter</td>
          <td align="right">$121</td>
          <td align="right">567</td>
          <td align="right">534.23%</td>
          <td>FishHead</td>
          <td align="right">06/06/2006</td>
         </tr>
         <tr class="alternateRow">
          <td>Jones</td>
          <td align="right">$15</td>
          <td align="right">11</td>
          <td align="right">15%</td>
          <td>Bubba</td>
          <td align="right">10/27/2005</td>
         </tr>
         <tr>
          <td>Supa-De-Dupa</td>
          <td align="right">$145</td>
          <td align="right">91</td>
          <td align="right">42%</td>
          <td>momma</td>
          <td align="right">12/15/1996</td>
         </tr>
         <tr class="alternateRow">
          <td>ClickClock</td>
          <td align="right">$1,213</td>
          <td align="right">23</td>
          <td align="right">2%</td>
          <td>Dada</td>
          <td align="right">1/30/1998</td>
         </tr>
         <tr>
          <td>Mrs. Robinson</td>
          <td align="right">$99</td>
          <td align="right">99</td>
          <td align="right">(-10.42%)</td>
          <td>Wife</td>
          <td align="right">07/04/1963</td>
         </tr>
         <tr class="alternateRow">
          <td>Maha</td>
          <td align="right">-$19,923.19</td>
          <td align="right">100</td>
          <td align="right">(-10.01%)</td>
          <td>Owner</td>
          <td align="right">01/02/2001</td>
         </tr>
         <tr>
          <td>Thrawl</td>
          <td align="right">$9,550</td>
          <td align="right">159</td>
          <td align="right">-10.20%</td>
          <td>Co-Owner</td>
          <td align="right">11/07/2003</td>
         </tr>
         <tr class="total">
          <td><strong>TOTAL</strong>:</td>
          <td align="right"><strong>999999</strong></td>
          <td align="right"><strong>9999999</strong></td>
          <td align="right"><strong>99</strong></td>
          <td > </td>
          <td align="right"> </td>
         </tr>
       </tbody>
      </table>
      </div>
      </td></tr>
      </table>
      </body>
      </html>
      

      【讨论】:

      • 是的,它适用于垂直滚动,但不适用于水平滚动。这是我在问题中提到的常见解决方案。
      • 这个解决方案与其他一些解决方案相比有一个主要优势,那就是表结构仍然完好无损并且有意义。对于仅锁定标题,它可能是最好的解决方案。
      • 感谢新先生的评论。毕竟这可能值得一点点提高(+1 投票)吗? (注意:这是一个社区帖子,对我来说没有代表增益)
      • 替换为 JSFiddle。
      【解决方案5】:

      这里有一个插件 JQuery:https://github.com/nitsugario/jQuery-Freeze-Table-Column-and-Rows

      这是一个jQuery插件,可以让表格的行和列不滚动。它可以获取给定的 HTML 表格对象并将其设置为可以冻结给定数量的列或行或两者,因此固定的列或行不会滚动。要冻结的行应该放在表头部分。它还可以结合使用 colspan 或 rowspan 属性来冻结行和列。

      【讨论】:

        【解决方案6】:

        你可以做到,无需 javascript

        查看此链接: http://yonax73.blogspot.com/2014/09/tabla-con-cabecera-estatica-cuerpo-con.html

        或现场演示: http://jsfiddle.net/yonatanalexis22/aeeme8mt/7/

        table{
        border-spacing: 0;
        display: flex;/*Se ajuste dinamicamente al tamano del dispositivo**/
        max-height: 40vh; /*El alto que necesitemos**/
        overflow-y: auto; /**El scroll verticalmente cuando sea necesario*/
        overflow-x: hidden;/*Sin scroll horizontal*/
        table-layout: fixed;/**Forzamos a que las filas tenga el mismo ancho**/
        width: 98vw; /*El ancho que necesitemos*/
        border:1px solid gray;}
        

        【讨论】:

        • 这似乎解决了另一个问题。在您链接的 jsfiddle 中,所有列都水平放置,因此没有水平滚动。我的部分问题提到了When you scroll right, the first column stays put, since it holds the labels for the rows. 如果它们不适合,您的 CSS 将隐藏那些不适合的 (overflow-x: hidden)。我尝试添加更多列,并删除该 CSS 规则,并且第一列从屏幕上滚动出来。这个“锁定第一列”部分使这成为一个难题。
        【解决方案7】:

        哦,好吧,我查找了具有固定列的可滚动表以了解此特定要求的需要,而您的问题就是其中之一,没有确切的答案..

        我回答了这个问题Large dynamically sized html table with a fixed scroll row and fixed scroll column,这激发了我作为插件展示我的工作https://github.com/meetselva/fixed-table-rows-cols

        该插件基本上将格式良好的 HTML 表格转换为具有固定表格标题和列的可滚动表格。

        用法如下,

        $('#myTable').fxdHdrCol({
            fixedCols    : 3,       /* 3 fixed columns */
            width        : "100%",  /* set the width of the container (fixed or percentage)*/
            height       : 500      /* set the height of the container */
        });
        

        您可以查看demo and documentation here

        【讨论】:

        • 这是一个不错的插件。有角版本的机会吗?
        • 我关注了您的出色工作,但我有一个问题,您是否必须为colModal 数组提供固定的列宽?我有一个列宽可变的表格,我似乎无法弄清楚如何让这个案例可以使用您的代码进行操作。我想知道这是否是对 colModal 的 width property width number Set the initial width of the column, in pixels. This value currently can not be set as percentage 的级联依赖
        【解决方案8】:

        今天有很多跨浏览器解决方案,其中有SuperTable,我喜欢它的优雅和简单(现在继续使用 MooGrid)和SlickGrid,它有一组很棒的功能。

        【讨论】:

          【解决方案9】:

          几周前我浏览了一个网站。这是第一列锁定的工作示例,但它与 Firefox 不兼容。我没有做很多检查,但它似乎只适用于 IE。作者提供了一些注释,您可以阅读。

          锁定第一列: http://home.tampabay.rr.com/bmerkey/examples/locked-column-csv.html

          如果您也需要 Javascript 来锁定表格标题,请告诉我。

          【讨论】:

          • 虽然这在理论上可以回答这个问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考……目前该链接无法访问,因此这是一个损坏的答案; (
          【解决方案10】:

          我在这里发布了我的 jQuery 插件解决方案:Frozen table header inside scrollable div

          它完全符合您的要求,而且非常轻巧且易于使用。

          【讨论】:

          • 这似乎不支持锁定第一列。还是我错过了什么?如果不是,那么这个解决方案并不比我在问题中提到的“通用”解决方案更好。
          • 我更新了我的演示页面,锁定了第一列演示。
          【解决方案11】:

          您需要两个表,其中第一个是第二个的精确覆盖。第二个包含所有数据,其中第一个仅包含第一列。您必须同步它的宽度,并根据内容同步它的行的高度。

          除了这两张表之外,您还需要第三张。这是第一行,正好位于其他两行之间,并且必须以相同的方式同步。

          这里需要绝对定位。接下来,将数据表的滚动与首行和第一列表的滚动位置同步。

          这在所有主流浏览器中都非常有效,除了一个问题:同步滚动会抖动。要解决这个问题,您需要两个外部 div 容器来保存标题行和第一列内容的克隆。垂直滚动时,显示标题行克隆以防止抖动,同时将原始行重新定位在背景中。 水平滚动时,您将显示第一行克隆。这里也一样。

          【讨论】:

          • 这比我最初想要的要复杂得多,但最终,这就是我最终要做的(或多或少)。看起来这应该比现在容易得多......
          • 我同意这似乎过于复杂,但我找不到任何其他解决方案。
          【解决方案12】:

          将表格的实际“数据”放在其自己的 div 中,overflow: scroll; 的解决方案怎么样?然后浏览器会自动为您不想锁定的“表格”部分创建滚动条,您可以将“表格标题”/第一行放在&lt;div&gt;上方。

          但不确定水平滚动如何工作。

          【讨论】:

          • 是的,它适用于垂直滚动,但不适用于水平滚动。这是我在问题中提到的常见解决方案。
          【解决方案13】:

          您必须对其进行测试,但如果您在页面中嵌入了 iframe,然后使用 CSS 将 iframe 页面中的第一行和第一列绝对定位在 0,0 处,是否可以解决您的问题?

          【讨论】:

          • 除非我误解了你,否则我认为这不会允许在数据滚动时更新标题(即,当数据向下滚动时向下滚动行标题,以便行标题仍然对应相应的行)。
          猜你喜欢
          • 1970-01-01
          • 2020-07-24
          • 2022-09-23
          • 2019-12-17
          • 1970-01-01
          • 2023-03-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多