Как заблокировать первый и последний столбцы таблицы html в прокручиваемом div?

У меня есть таблица со строкой заголовка, но также столбец заголовка и общий столбец с несколькими столбцами между ними.

Что-то вроде этого:

Name    Score 1    Score 2  ...  Total
--------------------------------------
John       5          6            86
Will       3          7            82
Nick       7          1            74

Вся таблица определена внутри прокручиваемого div с фиксированной шириной, потому что, вероятно, будет большое количество строк "Оценка", и у меня есть макет страницы с фиксированной шириной.

<div id="tableWrapper" style="overflow-x: auto; width: 500px;">
    <table id="scoreTable">
        ...
    </table>
</div>

Я хочу, чтобы первый (Name) и последний (Total) столбцы оставались видимыми во время прокрутки внутренних столбцов.

Может ли кто-нибудь помочь мне с этим?

Изменить: Я имею в виду только горизонтальную прокрутку - изменено, чтобы указать это.


Обновление: Я решил эту проблему для себя и разместил ответ ниже. Дайте мне знать, если вам нужна дополнительная информация - это было немного больно, и я бы не хотел, чтобы кто-то еще переписывал все.

Ответ 1

Я экспериментировал с несколькими методами (спасибо всем, кто помог), и вот, что я придумал с помощью jQuery. Кажется, он хорошо работает во всех браузерах, которые я тестировал. Не стесняйтесь взять его и использовать, как хотите. Следующий шаг для меня превратит его в многоразовый плагин jQuery.

Резюме:

Я начал с обычной таблицы со всем, что в ней (Id = "ladderTable" ), и я написал Три метода - один, чтобы удалить первый столбец, один для удаления последнего столбца и один для исправления высот строк.

Метод stripFirstColumn создает новую таблицу (Id = "nameTable" ), обходит исходную таблицу и вынимает первый столбец и добавляет эти ячейки в имяTable.

Метод stripLastColumn выполняет в основном одно и то же, за исключением того, что он вынимает последний столбец и добавляет ячейки в новую таблицу, называемую totalTable.

Метод fixHeights рассматривает каждую строку в каждой таблице, вычисляет максимальную высоту и применяет ее к связанным таблицам.

В событии, подготовленном документом, я вызывал все три метода в порядке. Обратите внимание, что все три таблицы плавают влево, поэтому они будут просто стек горизонтально.

Структура HTML:

<h1>Current Ladder</h1> 
<div id="nameTableSpan" style="float:left;width:100px;border-right:2px solid gray;"></div> 
<div id="ladderDiv" style="float:left;width:423px;overflow:auto;border:1px solid gray;margin-top:-1px;"> 
    <table id="ladderTable" class="ladderTable">
        <thead> 
            <tr><td>Name</td><td>Round 1</td> ... <td>Round 50</td><td class="scoreTotal">Total</td></tr>
        </thead>
        <tr><td>Bob</td><td>11</td> ... <td>75</td><td>421</td></tr>
           ... (more scores)
    </table>
</div>
<div id="totalTableSpan" style="float:left;width:70px;border-left:2px solid gray;"></div> 

jQuery:

function stripFirstColumn() {                
    // pull out first column:
    var nt = $('<table id="nameTable" cellpadding="3" cellspacing="0" style="width:100px;"></table>');
    $('#ladderTable tr').each(function(i)
    {
        nt.append('<tr><td style="color:'+$(this).children('td:first').css('color')+'">'+$(this).children('td:first').html()+'</td></tr>');
    });
    nt.appendTo('#nameTableSpan');
    // remove original first column
    $('#ladderTable tr').each(function(i)
    {
        $(this).children('td:first').remove();
    });
    $('#nameTable td:first').css('background-color','#8DB4B7');
}

function stripLastColumn() {                
    // pull out last column:
    var nt = $('<table id="totalTable" cellpadding="3" cellspacing="0" style="width:70px;"></table>');
    $('#ladderTable tr').each(function(i)
    {
        nt.append('<tr><td style="color:'+$(this).children('td:last').css('color')+'">'+$(this).children('td:last').html()+'</td></tr>');
    });
    nt.appendTo('#totalTableSpan');
    // remove original last column
    $('#ladderTable tr').each(function(i)
    {
        $(this).children('td:last').remove();
    });
    $('#totalTable td:first').css('background-color','#8DB4B7');
}

function fixHeights() {
    // change heights:
    var curRow = 1;
    $('#ladderTable tr').each(function(i){
        // get heights
        var c1 = $('#nameTable tr:nth-child('+curRow+')').height();    // column 1
        var c2 = $(this).height();    // column 2
        var c3 = $('#totalTable tr:nth-child('+curRow+')').height();    // column 3
        var maxHeight = Math.max(c1, Math.max(c2, c3));

        //$('#log').append('Row '+curRow+' c1=' + c1 +' c2=' + c2 +' c3=' + c3 +'  max height = '+maxHeight+'<br/>');

        // set heights
        //$('#nameTable tr:nth-child('+curRow+')').height(maxHeight);
        $('#nameTable tr:nth-child('+curRow+') td:first').height(maxHeight);
        //$('#log').append('NameTable: '+$('#nameTable tr:nth-child('+curRow+')').height()+'<br/>');
        //$(this).height(maxHeight);
        $(this).children('td:first').height(maxHeight);
        //$('#log').append('MainTable: '+$(this).height()+'<br/>');
        //$('#totalTable tr:nth-child('+curRow+')').height(maxHeight);
        $('#totalTable tr:nth-child('+curRow+') td:first').height(maxHeight);
        //$('#log').append('TotalTable: '+$('#totalTable tr:nth-child('+curRow+')').height()+'<br/>');

        curRow++;
    });

    if ($.browser.msie)
        $('#ladderDiv').height($('#ladderDiv').height()+18);
}

$(document).ready(function() {
    stripFirstColumn();
    stripLastColumn();
    fixHeights();
    $("#ladderDiv").attr('scrollLeft', $("#ladderDiv").attr('scrollWidth'));    // scroll to the last round
});

Если у вас есть какие-либо вопросы или есть что-то непонятное, я более чем счастлив помочь.

Мне потребовалось некоторое время, чтобы понять, что я ничего не могу повторить, и для написания этого потребовалось немного больше времени. Я бы не хотел, чтобы кто-то пошел на ту же проблему.

Ответ 2

Можно ли предложить несколько неортодоксальное решение?

Что вы думаете о размещении столбца "total" после столбца "name", а не в самом конце? Разве это не позволит избежать прокрутки только одной части таблицы?

Это не совсем то, о чем вы просите, но, возможно, это достаточное решение, учитывая, что альтернатива будет довольно грязной. (Например, размещение столбцов "total" и "name" за пределами таблицы создавало проблемы с выравниванием, если не все строки имеют равную высоту. Вы можете исправить это с помощью javascript, но затем вы войдете в совершенно новый мир боль).

Кроме того, с точки зрения пользовательского интерфейса, может быть, что "имя" и "общее" являются наиболее важными данными, и в этом случае было бы разумно объединить их, а затем "разбить" общий итог. Конечно, у нас, похоже, есть интуиция, что "сумма" должна появиться после его составных частей, но я не думаю, что это вызовет слишком много путаницы для пользователя, если бы порядок был отменен подобным образом (хотя это вопрос для вы, на основе вашего продукта и ваших пользователей).

В любом случае, что-то рассмотреть.

EDIT:

Вот еще несколько неортодоксальных решений, теперь, я думаю, я понимаю ваши намерения немного лучше:

  • Нарисуйте оценки. Дайте последние десять, скажем, и общее, и ссылка на более старые баллы, которые предоставляются 10 за раз.
  • Укажите имена, итоги и некоторые другие значимые меры таких как среднее и sd, затем предоставить ссылка для каждого имени, которое показывает все результаты, соответствующие этому имя. Тогда вы могли бы также предоставить ссылка, показывающая все результаты для данный набор баллов, так что сравнения между разными пользователями могут быть сделаны. Дело в том, что вы только нужно дать 1 размер данных для каждого вида, а не с громоздким двумерным набором данных
  • Сделайте строки сортируемыми (легко с пользовательским интерфейсом jQuery), чтобы, если я хочу сравните Мэри с Джейн, я могу перетащить и место один за другим, так что я не буду нужно держать прокрутку влево и влево право видеть, какие результаты соответствуют к которым имена
  • Выделите строку при щелчке, изменив фон цвет или аналогичный, снова, поэтому мне не нужно держать прокрутку влево и вправо.

В любом случае вы получаете идею. Возможно, лучше искать решение для пользовательского интерфейса, чем исправленное решение разметки. В конечном счете, я бы поставил под вопрос, насколько важно представлять так много данных пользователю сразу, что часть его должна прокручиваться определенным образом, чтобы данные могли быть прочитаны. Возможно, вы создаете приложение для работы с электронными таблицами, и вам действительно нужно отображать матрицу 100x100 в одном представлении. Если нет, вы могли бы придумать более творческие пути, чем я должен разделить результаты.

Ответ 4

Я предполагаю, что вы хотите прокручивать его только по горизонтали. В противном случае это может запутать статические столбцы.

Вы можете поместить переполнение: auto на содержащий элемент внутренних ячеек таблицы... Я не уверен, как браузеры справятся с этим, но вы можете поместить элементы, которые вы хотите зафиксировать внутри thead и tfoot элементов и поместите прокручиваемую часть внутри элемента tbody и установите для него переполнение в auto.

В противном случае вам может потребоваться сбросить семантику и закодировать левый столбец и правый столбец вне таблицы.

Лично я попробую сделать это как семантическое, а затем использовать JavaScript для размещения левого и правого столбцов. Без JavaScript вы должны сделать это изящно из-за большого стола (не уверен, насколько это было бы сложно, как вы говорите, у вас есть фиксированная ширина)

Вы можете попробовать этот (грубый) пример jQuery, чтобы поместить первые значения столбца снаружи.

var nameTable = '<table id="outside-name-col">
                  <thead>
                   <tr>
                    <th>Name</th>
                   </tr>
                  </thead>
                 <tbody>'; // start making a table for name column only

$('#scoreTable tbody tr').each(function() { // iterate through existing table

   var nameCol = $(this).find(':first'); // get column of index 0, i.e. first

   var cellHeight = nameCol.height(); // get the height of this cell

   $(this).find('td').height(cellHeight); // equalise the height across the row so removing this element will not collapse the height if it is taller than the scores and total       

   nameTable += '<tr><td style="height: ' + cellHeight + 'px">' + nameCol.html() + '</td></tr>'; // append the next row with new height and data

   nameCol.remove(); // remove this cell from the table now it been placed outside

});

nameTable += '</tbody></table>'; // finish table string


$('#scoreTable').before(nameTable); // insert just before the score table

Используйте CSS, чтобы правильно их выровнять. Это не проверено, но оно должно дать вам некоторую идею.

Ответ 5

Теперь это не совсем правильно (я просто издевался над ним очень быстро), но вот способ сделать это с использованием прямого HTML. Вы хотите, чтобы три таблицы... два вне <div> и один внутри <div> . Все три плавают влево, так что все они находятся на одной линии.

Тестирование таблиц

и сам код:

  <table style="float: left;">
     <tr>
        <td>Name</td>
     </tr>
     <tr>
        <td>John</td>
     </tr>
     <tr>
        <td>Will</td>
     </tr>
  </table>
  <div id="tableWrapper" style="overflow-x: auto; width: 500px;float:left;padding-bottom: 10px;">
      <table>
        <tr>
           <td>Score1</td>
           <td>Score2</td>
           ...
        </tr>
        <tr>
           <td>5</td>
           <td>6</td>
           ...
        </tr>
        <tr>
           <td>3</td>
           <td>7</td>
           ...
        </tr>
        <tr>
           <td>7</td>
           <td>1</td>
           ...
        </tr>
      </table>
  </div>
  <table style="float: left;">
     <tr>
        <td>Total</td>
     </tr>
     <tr>
        <td>86</td>
     </tr>
     <tr>
        <td>82</td>
     </tr>
  </table>

Примечание. Нижняя часть дна на div такова, что полоса прокрутки не закрывает таблицу в IE. Кроме того, ошибка, которую я должен решить, заключается в том, как указать ширину элементов заголовка внутри средней таблицы. По какой-то причине указание атрибута width = "" не работает. Таким образом, если текст элемента заголовка слишком широк (и разбивается на другую строку), тогда макет разбивается (отключается на одну строку)

Ответ 6

Значит ли u горизонтальная прокрутка??

Если вы хотите добиться горизонтальной прокрутки, вы можете использовать 3 контейнера.

  • Для первого столбца (Имя)
  • Для столбцов, которые вы хотите прокрутить. Задайте стиль переполнения x для этого контейнера автоматически.
  • Для последнего столбца (Всего)

Ответ 7

Прокрутка содержимого таблиц является проблематичной проблемой, поскольку для достижения этого не существует простого и безопасного для браузера решения.

Лучший и наиболее безопасный способ для этого требует JavaScript. Вы бы достигли даже горизонтальной прокрутки легко (он был включен бесплатно) с использованием этой техники, которую я использовал. Вы можете легко преобразовать это в свою проблему:

1) Я сделал 3 таблицы

2) Размещается средняя таблица, содержащая данные внутри контейнера DIV

3) установите стиль DIV для переполнения: auto

4) дал таблицу заголовка и нижнего колонтитула, а div - ширину 100%

5) окружили все другим div, чтобы управлять общей шириной таблицы

6) убедился, что количество столбцов совпадает во всех трех таблицах, и что все три имеют одинаковые стили в отношении прокладок, полей и границ.

теперь интересная часть:

6) ниже последнего элемента этой таблицы, напишите блок javascript (или включите его из файла)

7) напишите функцию, которая последовательно смотрит на каждый столбец (используйте цикл for), начиная с первого. На каждой итерации этого цикла проверьте ячейку td на первые две таблицы в текущем столбце. Проверьте, какой из них является более крупным, и назначьте его меньшему типу ячейки td. Вы также можете применить это значение к таблице нижнего колонтитула.

8) вызовите эту функцию. Вы можете сделать это через интервал или когда происходят особые события, такие как новые данные в ячейках (например, при использовании ajax).

Примечание. Если вы выполняете горизонтальную прокрутку, ваши размеры столбцов синхронизируются. Но вам придется синхронизировать положение прокрутки таблицы заголовка и нижнего колонтитула с таблицей содержимого. В качестве альтернативы вы просто позволяете общему div прокручивать все это по горизонтали, но не по вертикали. Это будет задачей DIV, которая содержит таблицу данных.

Этот метод очень хорошо работал во всех основных браузерах в проекте очень коплексной диаграммы gantt.

Примечание. Вы можете легко мыслить эту концепцию с помощью поворота на 90 градусов, чтобы вы могли зафиксировать первый и последний столбцы заголовка при прокрутке.

Изменить: Вот еще один пример из моей базы кода, который поможет вам получить решение:

var left_td = document.getElementById("left_td");
var right_td = document.getElementById("right_td");
var contentDiv = document.getElementById("contentDiv");
window.setInterval(function(){
    var left_td_width = Math.round((parseInt(contentDIV.offsetWidth) - 120) / 2);
    var right_td_width = (parseInt(contentDIV.offsetWidth) - left_td_width - 120;

    left_td.style.width = left_td_width + "px";
    right_td.style.width = right_td_width + "px";
}, 25);

Этот код делает следующее: он гарантирует, что таблица с тремя столбцами всегда выглядит так: первый и последний столбцы имеют одинаковый размер, а центральный столбец имеет ширину 120 пикселей. Конечно, это не относится непосредственно к вашей особой проблеме, но может дать вам отправную точку в динамической обработке таблиц с помощью JavaScript.