固定第一列的水平和垂直滚动的HTML表

时间:2018-11-16 06:10:02

标签: javascript html css

表头是固定的,表定义是可滚动的(水平和垂直),但我需要将列(th和td)固定到国家/地区,并且滚动应该从文本标题/文本定义列开始。浏览器窗口不应水平滚动。

CSS

table {
    font-family: arial, sans-serif;
    border-collapse: collapse;
    max-height: 500px;
    width: 100%;
    overflow: auto;
    display: block;
}

td, th {
    border: 1px solid #dddddd;
    text-align: left;
    padding: 8px;
    /*width: 400px !important;*/
}
th{
    position: sticky;
    top:0;
    background: #e2e0e2;
}

HTML

    <table>
        <tr>
            <th>Company</th>
            <th>Address</th>
            <th>Contact</th>
            <th>City</th>
            <th>State</th>
            <th>Zip</th>
            <th>Country</th>
            <th>Table Heading</th>
            <th>Table Heading</th>
        </tr>

        <tr>
            <td>Alfreds Futterkiste</td>
            <td>Address1</td>
            <td>Maria Anders</td>
            <td>City Name</td>
            <td>State Name</td>
            <td>Zipcode</td>
            <td>Germany</td>
            <td>Table definition</td>
            <td>Table definition</td>
        </tr>
        <tr>
            <td>Alfreds Futterkiste</td>
            <td>Address1</td>
            <td>Maria Anders</td>
            <td>City Name</td>
            <td>State Name</td>
            <td>Zipcode</td>
            <td>Germany</td>
            <td>Table definition</td>
            <td>Table definition</td>
        </tr>
    </table>

js fiddle here

2 个答案:

答案 0 :(得分:0)

我刚刚发现了一个jquery插件,您可以使用它来实现垂直滚动的固定标题。

http://www.fixedheadertable.com

注意:将fixedColumn设置为true可使水平滚动工作。

答案 1 :(得分:0)

<html>
      <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
        <script>

  @author:   Conan Albrecht <ca@byu.edu>
  @version:  1.1
  @modified: 2012-02-29
  @license:  Public Domain; No warranty of any kind is given.  Use at your own risk.

  A JQuery plugin to freeze table columns and headers -- spreadsheet style.

    * Any items in the <thead> are frozen as headers.
    * The given number of columns are frozen.

  Please note that this is a big hack on the <table> tag in HTML.  The script takes your table
  and splits it into 4 tables: 
    Region 1    Region 2
    Region 3    Region 4

    - Region 1 is the top-left corner cell (or cells for multiple frozen columns/headers)
    - Region 2 is your <thead> cells, less the ones pulled off the left
    - Region 3 is your frozen columns on the left side.
    - Region 4 is the regular, unfrozen data of the table.

    The script keeps the row height of Regions 3 and 4 the same, and it keeps the column width of
    Regions 1 and 3/2 and 4 the same.  That makes the user think it's one big table still.
    When either Region 3 or 4 are scrolled, the script matches the other tables to it.

    The script makes four copies of your table, then deletes rows and columns as needed.  This ensures that
    the table/row/cell properties, events, etc. move into each area.  This approach works well with regular-sized
    tables, but it won't be efficient with huge tables.

  Options:
    The script takes several options.  All of these are listed (with comments) in the example below.

  Known issues:

    * It works with columns that span (<td colspan="">), but *at least one <tr>* in each region must be
      free of colspans.  In other words, you can span columns all you want, but you must leave at least 
      one row a normal row with non-spanning columns in each of the four regions.  The algorithm in this
      script uses this non-colspanning row to figure out column widths.  In addition, tables can behave
      erratically when columns are spanned no the first row.  YMMV.
    * It has to allow the tables unlimited width to get a calculation of how big they need to be.  This
      "unlimited" width is currently set at 50,000 pixels.  You may want to adjust this if your table
      is bigger than this (wow!) or subsantially smaller (to save memory).
    * It doesn't support freezing of <tfoot> areas.
*/

(function( $ ) {
  $.fn.freezeTableColumns = function(options) {
    options = initOptions(options);
        var source_table = $(this);
        var main_id = source_table.attr('id');
        if (!main_id) {
          console.log('jquery.freezetablecolumns.js: Error initializing frozen columns - source table must have a unique id attribute.');
          return;
      }

        // set up the four regions
        source_table.after('<div id="' + main_id + '-div" style="display: inline-block;"></div>');
        source_table.detach(); // remove the table from the document flow
        main_div = $('#' + main_id + '-div');
        main_div.append(
          '<div id="' + main_id + '-row1" style="white-space: nowrap;">' + 
          '<div id="' + main_id + '-region1" style="display: inline-block; vertical-align: top; width: 5px; overflow: hidden;"><div></div></div>' + 
      '<div id="' + main_id + '-region2" style="display: inline-block; vertical-align: top; width: 5px; overflow-x: hidden; overflow-y: scroll;"><div></div></div>' + 
          '</div>'
        );
        main_div.append(
      '<div id="' + main_id + '-row2"  style="white-space: nowrap;">' +
          '<div id="' + main_id + '-region3" style="display: inline-block; vertical-align: top; height: 100%; width: 5px; overflow-y: hidden; overflow-x: scroll;"><div></div></div>' + 
      '<div id="' + main_id + '-region4" style="display: inline-block; vertical-align: top; height: 100%; width: 5px; overflow: scroll;"><div></div></div>' + 
        '</div>'
      );

        // row 1 (corner area and header divs)
        // note that I use .children() rather than .find() in case the user's table cells have additional tables embedded within them
        var source_table_region1 = source_table.get(0).cloneNode(false);
        $(source_table_region1).removeAttr('id'); // only one of the four tables can have the original id
    moveElement(source_table_region1, $('#' + main_id + '-region1').children('div'));
    $('#' + main_id + '-region1').children('div').children('table').append('<thead></thead>');
    var thead = $('#' + main_id + '-region1 > div > table > thead');
    source_table.children('thead').children('tr').each(function(rowindex, rowelement) {
      thead.append('<tr></tr>');
      var tr = thead.children('tr:last');
      var cellindex = 0;
      $(rowelement).children('td,th').each(function() {
        if (cellindex >= options.numFrozen) {
          return false;
        }
        moveElement(this, tr);
        if (typeof $(this).attr('colspan') === "undefined") {
          cellindex += 1;
        }else{
          cellindex += $(this).attr('colspan');
        }
      });
    });
    var source_table_region2 = source_table.get(0).cloneNode(false);
        $(source_table_region2).removeAttr('id'); // only one of the four tables can have the original id
    moveElement(source_table_region2, $('#' + main_id + '-region2').children('div')); // second table is easier because we already removed the frozen td's -- just add what's left in the thead
        moveElement(source_table.children('thead'), $('#' + main_id + '-region2').children('div').children('table'));

    // row 2 (frozen columns and main data table divs)
    var source_table_region3 = source_table.get(0).cloneNode(false);
        $(source_table_region3).removeAttr('id'); // only one of the four tables can have the original id
    moveElement(source_table_region3, $('#' + main_id + '-region3').children('div'));
    $('#' + main_id + '-region3').children('div').children('table').append('<tbody></tbody>');
    var tbody = $('#' + main_id + '-region3 > div > table > tbody');
    source_table.children('tbody').children('tr').each(function(rowindex, rowelement) {
      tbody.append('<tr></tr>');
      var tr = tbody.children('tr:last');
      var cellindex = 0;
      $(rowelement).children('td,th').each(function() {
        if (cellindex >= options.numFrozen) {
          return false;
        }
        moveElement(this, tr);
        if (typeof $(this).attr('colspan') === "undefined") {
          cellindex += 1;
        }else{
          cellindex += $(this).attr('colspan');
        }
      });
    });
    moveElement(source_table, $('#' + main_id + '-region4').children('div')) // move whatever is left in the table

    // set to fixed-with
    for (var i = 1; i <= 4; i++) {
      $('#' + main_id + '-region' + i).children('div').children('table').css('table-layout', 'fixed');
    }

    // lay everything out
    source_table.freezeTableColumnsLayout(options);

    // set up the events to match elements when scrolled
    var scroll_affects = {  // source -> xscroll, yscroll
      '-region1': [ '-region3', '-region2' ],
      '-region2': [ '-region4', '-region1' ],
      '-region3': [ '-region1', '-region4' ],
      '-region4': [ '-region2', '-region3' ],
    }
    main_div.children('div').children('div').scroll(function(event) {
      var sourceid = $(this).attr('id').substr($(this).attr('id').lastIndexOf('-'));
      $('#' + main_id + scroll_affects[sourceid][0]).scrollLeft($(this).scrollLeft());
      $('#' + main_id + scroll_affects[sourceid][1]).scrollTop($(this).scrollTop());
    });//scroll

  };//freezeTableColumns


  /* 
    Moves an element to a new parent.  I use the Javascript DOM methods here because
    JQuery's append strips and evaluates any attached javascript the user has in the table.
    This is not what the user expects, so move the table elements using DOM.
    I use this method any time I'm moving existing HTML I didn't place in the document.
  */
  function moveElement(element, newparent) {
    $(element).each(function(eindex, e) {
      $(newparent).get(0).appendChild(e);
    });
  }


  /* 
    Adjusts the widths to an already-existing frozen table.  This allows you to adjust the main div height or width,
    cell contents, etc., and then lay everything out again.  The options are the same as the main function, but
    you can't change the number of frozen columns.  See the example at the top for, well, an example.
  */
  $.fn.freezeTableColumnsLayout = function(options) {
    options = initOptions(options);
    var main_id = $(this).attr('id');

        // make all the columns the same width
        function setColWidths(topRegion, bottomRegion) {
          // clear the widths if needed
          if (options.clearWidths) {
          topRegion.children('div').children('table').width('');
          bottomRegion.children('div').children('table').width('');
            topRegion.children('div').children('table').children('thead,tbody').children('tr').children('td,th').each(function() {
              $(this).removeAttr('width');
              $(this).css('width', '');
          });
            bottomRegion.children('div').children('table').children('thead,tbody').children('tr').children('td,th').each(function() {
              $(this).removeAttr('width');
              $(this).css('width', '');
          });
        }
          // find the first <tr> without any colspan attributes (those mess up the algorithm)
          var top_tr = null;
          topRegion.children('div').children('table').children('thead,tbody').children('tr').each(function(index) {
            if ($(this).children('td,th').filter('[colspan]').length == 0) { // i.e. this row has no colspans
            top_tr = $(this);
            return false;
          }
        });
          var bottom_tr = null;
          bottomRegion.children('div').children('table').children('thead,tbody').children('tr').each(function(index) {
            if ($(this).children('td,th').filter('[colspan]').length == 0) { // i.e. this row has no colspans
            bottom_tr = $(this);
            return false;
          }
        });
        if (top_tr == null || bottom_tr == null) {
          return;
      }
        // set the widths of each column
        topRegion.children('div').children('table').children('colgroup').remove();
        topRegion.children('div').children('table').prepend('<colgroup></colgroup>');
        bottomRegion.children('div').children('table').children('colgroup').remove();
        bottomRegion.children('div').children('table').prepend('<colgroup></colgroup>');
        top_tr.children('td,th').each(function(index) {
          var bottomcell = bottom_tr.children('td,th').eq(index);
          var maxwidth = Math.max($(this).width(), bottomcell.width()) + 10;
          topRegion.children('div').children('table').children('colgroup').append('<col width="' + maxwidth + '"/>');
          bottomRegion.children('div').children('table').children('colgroup').append('<col width="' + maxwidth + '"/>');
      });//each
    }//setColWidths function
    setColWidths($('#' + main_id + '-region1'), $('#' + main_id + '-region3'));
    setColWidths($('#' + main_id + '-region2'), $('#' + main_id + '-region4'));

    // make all the rows the same height
    function setRowHeights(left_region, right_region) {
      left_region.children('div').children('table').children('thead,tbody').children('tr').each(function(index) {
        var right_region_tr = right_region.children('div').children('table').children('tbody,thead').children('tr').eq(index);
        var maxheight = Math.max($(this).height(), right_region_tr.height());
        $(this).height(maxheight);
        right_region_tr.height(maxheight);
      });
    }//setRowHeights
    setRowHeights($('#' + main_id + '-region1'), $('#' + main_id + '-region2'));
    setRowHeights($('#' + main_id + '-region3'), $('#' + main_id + '-region4'));

        // set row 2 height to follow the required height
        var row1height = $('#' + main_id + '-div').children('#' + main_id + '-row1').outerHeight();
        $('#' + main_id + '-div').children('#' + main_id + '-row2').height(options.height - row1height);

    // calculate how big the tables want to be, given an "unlimited" space (50,000 in this case)
    $('#' + main_id + '-region1').children('div').width(5000);
    $('#' + main_id + '-region2').children('div').width(5000);
    $('#' + main_id + '-region3').children('div').width(5000);
    $('#' + main_id + '-region4').children('div').width(5000);
    var region1_3div = Math.max($('#' + main_id + '-region1').children('div').children('table').outerWidth(), $('#' + main_id + '-region3').children('div').children('table').outerWidth());
    var region2_4div = Math.max($('#' + main_id + '-region1').children('div').children('table').outerWidth(), $('#' + main_id + '-region4').children('div').children('table').outerWidth());
    if (options.frozenWidth < 0) {
      options.frozenWidth = region1_3div;
    }

    // set the widths for both the containing divs (with the overflow scrolls) and the inner divs (that give the tables all the room they want)
    $('#' + main_id + '-region1').width(options.frozenWidth);
    $('#' + main_id + '-region1').children('div').width(region1_3div);
    $('#' + main_id + '-region2').width(options.width - options.frozenWidth);
    $('#' + main_id + '-region2').children('div').width(region2_4div);
    $('#' + main_id + '-region3').width(options.frozenWidth);
    $('#' + main_id + '-region3').children('div').width(region1_3div);
    $('#' + main_id + '-region4').width(options.width - options.frozenWidth);
    $('#' + main_id + '-region4').children('div').width(region2_4div);
  };//freezeTableColumnsLayout


  /* Initializes the options with default values - not meant to be called externally */
  function initOptions(options) {
        return $.extend({
      width:       800,
      height:      800,
      numFrozen:   1,
      frozenWidth: -1, // default is dynamic
      clearWidths: true,
        }, options || {});//extend
  };//initOptions  

})( jQuery );
        </script>
          <style type="text/css">
            #mytable-div table {
              border-collapse: collapse;
            }
            #mytable-div td,th {
              border: 1px solid #B3B3B3;
              white-space: nowrap;
              padding: 2px 4px;
            }
          </style>
      </head>
      <body>
        <script>
          $(document).ready(function() {

            // freeze the columns
            $('#mytable').freezeTableColumns({
              width:       $(window).width(),   // required (exact px here, not % or em)
              height:      300,                 // required (exact px here, not % or em)
              numFrozen:   2,                   // optional, defaults to 1 left-most column frozen
           // frozenWidth: 200,                 // optional, defaults to natural width of frozen columns
           // clearWidths: true,                // optional, defaults to true, meaning that any set widths on the columns are cleared
            });//freezeTableColumns

            // example of adjusting the table once it is already displayed (note I'm calling freezeTableColumnsLayout() this time)
            $('#mybutton').click(function() {
              $('#mytable').freezeTableColumnsLayout({
                width:       $(window).width(), // new width of table
                height:      300, // new height of table
                //frozenWidth: 125, // specify the frozen width this time
                numFrozen:   2,   // this option won't do anything -- you can't change the number of frozen cols after initial display
              });
            });//click
          });//ready
        </script>
        <!-- <div><button id="mybutton">Adjust the Layout After Display (just another example)</button></div> -->
        <table id="mytable">

          <thead>
            <tr>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
              <th>&nbsp;Column here</th>
            </tr>
          </thead>

          <tbody>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
            <tr>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
              <td>&nbsp;Row and column</td>
            </tr>
          </tbody>

        </table>
      </body>
      </html>