Таблица с фиксированной шапкой на JavaScript
В одном из рабочих проектов появилась необходимость выводить достаточно длинную таблицу с большим количеством однотипных колонок. При вертикальной прокрутке заголовок таблицы уезжает, и уже на втором скролле становится очень сложно сориентироваться, какая из колонок к чему относится. Проблема решается с помощью создания фиксированной шапки у таблицы, которая всегда будет отображаться, пока "родной" заголовок таблицы находится за пределами видимой области страницы.Начнем с верстки. Для корректной работы скрипта нужно выполнение всего несколько требований. Таблица, у которой будет фиксироваться заголовок, обязательно должна иметь атрибут id и фиксированную ширину. Шапка таблицы должна быть обрамлена тегом thead. Например:
Code (HTML) : Убрать нумерацию
- <table id="my_table" style="width:980px;" rules="all">
- <thead>
- <tr>
- <th style="width:20px;">N</th>
- <th style="background: #BABABA;">Наименование</th>
- <th>Описание</th>
- <th style="width:60px;">Цена</th>
- <th style="width:60px;">Количество</th>
- <th style="width:60px;">Сумма</th>
- </tr>
- </thead>
- <tr>
- <td>1</td>
- <td>Предмет 1</td>
- <td>Описание 1</td>
- <td>26</td>
- <td>97</td>
- <td>2522</td>
- </tr>
- ... остальное содержимое таблицы
- </table>
А вот сам скрипт, который надо подключить к странице. Можно вынести его в отдельный файл или добавить прямо в HTML-код, кому как нравится.
Code (JavaScript) : Убрать нумерацию
- //-----------------------------------------------------
- // Фиксированный заголовок у таблицы
- //-----------------------------------------------------
- // by ManHunter / PCL (www.manhunter.ru)
- //-----------------------------------------------------
- fix_header={
- 'fixed_el': null,
- 'new_table': null,
- bind : function(el, eventName, callback) {
- if (el) {
- if (el.addEventListener) {
- el.addEventListener(eventName, callback, false);
- }
- else if (el.attachEvent) {
- el.attachEvent("on" + eventName, callback);
- }
- }
- },
- get_position: function(el) {
- var offsetLeft = 0, offsetTop = 0;
- do {
- offsetLeft += el.offsetLeft;
- offsetTop += el.offsetTop;
- }
- while (el = el.offsetParent);
- return {x:offsetLeft, y:offsetTop};
- },
- chk_position: function() {
- var doc = document.documentElement;
- var body = document.body;
- if (typeof(window.innerWidth) == 'number') {
- my_width = window.innerWidth;
- my_height = window.innerHeight;
- }
- else if (doc && (doc.clientWidth || doc.clientHeight)) {
- my_width = doc.clientWidth;
- my_height = doc.clientHeight;
- }
- else if (body && (body.clientWidth || body.clientHeight)) {
- my_width = body.clientWidth;
- my_height = body.clientHeight;
- }
- if (doc.scrollTop) { dy=doc.scrollTop; } else { dy=body.scrollTop; }
- var coord=fix_header.get_position(fix_header.fixed_el);
- // Заголовок таблицы еще на экране или таблица уже не на экране
- if (coord.y>dy || (coord.y+fix_header.fixed_el.clientHeight)<dy) {
- fix_header.new_table.style.left='-9999px';
- }
- // Заголовок уже прокручен вверх
- else {
- fix_header.new_table.style.left=
- fix_header.fixed_el.getBoundingClientRect().left+'px';
- }
- },
- fix: function (id) {
- var tmp,st;
- var ftable=document.getElementById(id);
- if (ftable) {
- if (this.new_table!=null) {
- if (this.new_table.parentNode!=undefined) {
- this.new_table.parentNode.removeChild(this.new_table);
- }
- this.new_table=null;
- }
- else {
- this.bind(window,'scroll',this.chk_position);
- this.bind(window,'resize',this.chk_position);
- }
- this.fixed_el=ftable;
- tmp=ftable.getElementsByTagName('thead');
- if (tmp) {
- var fthead=tmp[0];
- new_table=document.createElement('table');
- for(var i in this.fixed_el.style) {
- if (this.fixed_el.style[i]!='') {
- try {
- new_table.style[i]=this.fixed_el.style[i];
- }
- catch (e) {};
- }
- }
- new_table.id='fixed_'+id;
- new_table.rules='all';
- new_table.border='1';
- new_table.style.position='fixed';
- new_table.style.left='-9999px';
- new_table.style.top='0px';
- var cln = fthead.cloneNode(true);
- var cth=cln.getElementsByTagName('th');
- var fth=fthead.getElementsByTagName('th');
- for(var i=0; i<fth.length; i++) {
- cth[i].style.width=(fth[i].clientWidth+(window.opera?1:0))+'px';
- cth[i].style.paddingLeft='0';
- cth[i].style.paddingRight='0';
- }
- new_table.appendChild(cln);
- this.fixed_el.parentNode.appendChild(new_table);
- this.new_table=new_table;
- this.chk_position();
- }
- }
- }
- };
Code (JavaScript) : Убрать нумерацию
- fix_header.fix('my_table');
Рабочий пример скрипта из статьи и таблицы с фиксированным заголовком можно посмотреть на демонстрационной странице.
Просмотров: 9537 | Комментариев: 8
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(28.09.2017 в 11:17):
Ну так чо сам не сделал?
Михаил
(28.09.2017 в 11:11):
Не респонсив хоть кто может сделать
ManHunter
(04.05.2016 в 12:09):
Нет предела совершенству :)
Lyfeh
(04.05.2016 в 11:06):
Приветствую ManHunter! У меня была похожая идея, но никак руки не доходили. Ваш труд очень выручил меня в реализации плавающей многоэтажной шапки. Большое человеческое спасибо! Добавлю от себя немного фикса:
1) В вашем варианте не учитывается "colgroup", доработал:
// необходимо добавить после 84 строчки new_table=document.createElement('table');
tmp = ftable.getElementsByTagName('colgroup');
if (tmp) {
var fcolgroup=tmp[0];
if (fcolgroup) {
var clncolgroup = fcolgroup.cloneNode(true);
new_table.appendChild(clncolgroup);
}
}
2) при открытии html шапка отображается сверху, пофиксил добавил в 53 строчку знак "=" (т.е. условие было coord.y>dy, 0>0 шапка отображалась, сделал coord.y>=dy, 0>=0 шапки нет, все ОК), получилось:
// Заголовок таблицы еще на экране или таблица уже не на экране
if (coord.y>=dy || (coord.y+fix_header.fixed_el.clientHeight)<dy) {
1) В вашем варианте не учитывается "colgroup", доработал:
// необходимо добавить после 84 строчки new_table=document.createElement('table');
tmp = ftable.getElementsByTagName('colgroup');
if (tmp) {
var fcolgroup=tmp[0];
if (fcolgroup) {
var clncolgroup = fcolgroup.cloneNode(true);
new_table.appendChild(clncolgroup);
}
}
2) при открытии html шапка отображается сверху, пофиксил добавил в 53 строчку знак "=" (т.е. условие было coord.y>dy, 0>0 шапка отображалась, сделал coord.y>=dy, 0>=0 шапки нет, все ОК), получилось:
// Заголовок таблицы еще на экране или таблица уже не на экране
if (coord.y>=dy || (coord.y+fix_header.fixed_el.clientHeight)<dy) {
ManHunter
(25.04.2016 в 17:20):
Сайт без скриптов подобен сайту со скриптами, только без скриптов :)
Хотя по факту не меньше половины современных сайтов с отключенными скриптами даже не отобразятся корректно, не говоря уже о работоспособности, тут их будет чуть меньше, чем все.
Хотя по факту не меньше половины современных сайтов с отключенными скриптами даже не отобразятся корректно, не говоря уже о работоспособности, тут их будет чуть меньше, чем все.
Infocatcher
(25.04.2016 в 11:53):
Угу. Хотя все равно приятнее, когда сайт без скриптов работает.
ManHunter
(25.04.2016 в 11:43):
Так если б position:sticky еще и всеми браузерами поддерживалось, не пришлось бы ничего изобретать. А так один фиг для совместимости точно так же пришлось бы делать свои решения.
Infocatcher
(25.04.2016 в 11:18):
Жаль, вот эта экспериментальная штука как-то подзастряла:
https://developer.mozilla.org/..._positioning
https://developer.mozilla.org/..._positioning
Добавить комментарий
Заполните форму для добавления комментария