Skip to content

Instantly share code, notes, and snippets.

@amorkovin
Last active January 4, 2021 18:18
Show Gist options
  • Save amorkovin/358eeebe6ea9e22d4f4cba3ae26362c3 to your computer and use it in GitHub Desktop.
Save amorkovin/358eeebe6ea9e22d4f4cba3ae26362c3 to your computer and use it in GitHub Desktop.
Кнопки для горизонтальной прокрутки таблицы
// HTML
<div class="trading-page__pricing-table-wrap table-wrap">
<div class="table-wrap__inner">
<table>
...
</table>
</div>
</div>
// CSS
.table-wrap {
position: relative;
}
.table-wrap__inner {
width: 100%;
height: 100%;
overflow: scroll;
}
.table-wrap table {
width: 100%;
}
.table-wrap .arrow-scroll {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 20px;
background: Silver;
opacity: 0.3;
text-indent: -9999px;
border: none;
}
.table-wrap .arrow-scroll:active {
opacity: 1;
}
.table-wrap .arrow-scroll::before {
content: '<';
text-indent: 0;
color: DimGrey;
position: absolute;
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
}
.table-wrap .arrow-scroll.arrow-right {
left: auto;
right: 0;
}
.table-wrap .arrow-scroll.arrow-right::before {
content: '>';
}
//JS
document.addEventListener("DOMContentLoaded", function () {
const initializedTables = manTableScrollInit();
manTablesScrollInitAfterResizeBrowsr(initializedTables);
listenResizeBrowser(manTablesScrollInitAfterResizeBrowsr, initializedTables);
});
function manTableScrollInit() {
const initializedTables = [];
const tables = document.querySelectorAll('.table-wrap table');
if (tables.length) {
tables.forEach((tableItem) => {
const tableHeight = tableItem.clientHeight;
const inner = tableItem.parentElement;
// Прячу стандартную полосу горизонтальной прокрутки (она прячется за границами блока inner)
inner.style.height = tableHeight + 'px';
const arrowLeft = document.createElement('button');
arrowLeft.classList.add('arrow-scroll');
arrowLeft.classList.add('arrow-left');
arrowLeft.textContent = 'To the left';
const arrowRight = document.createElement('button');
arrowRight.classList.add('arrow-scroll');
arrowRight.classList.add('arrow-right');
arrowRight.textContent = 'To the right';
inner.append(arrowLeft);
inner.append(arrowRight);
if (inner.scrollLeft === 0) {
arrowLeft.style.display = 'none';
} else {
arrowLeft.style.display = 'block';
}
if (inner.scrollWidth === inner.clientWidth) {
arrowRight.style.display = 'none';
} else {
arrowRight.style.display = 'block';
}
// Прослушиваю клики по кнопкам
arrowLeft.addEventListener('click', (e) => {
manSingleScrollBtnClick(e);
});
arrowRight.addEventListener('click', (e) => {
manSingleScrollBtnClick(e);
});
listenerScrollBarBrowserScrollTable(tableItem);
listenerWindowResizeForTableScroll(tableItem);
initializedTables.push(tableItem);
});
}
return initializedTables;
}
function manTablesScrollInitAfterResizeBrowsr(initializedTables) {
if (!initializedTables.length) {
return;
}
initializedTables.forEach(tableItem => {
const wrapper = tableItem.parentElement;
const scrollRightBtn = tableItem.parentElement.querySelector('.arrow-right');
const tableHeight = tableItem.clientHeight;
// Прячу стандартную полосу горизонтальной прокрутки (она прячется за границами блока inner)
wrapper.style.height = tableHeight + 'px';
if (wrapper.scrollWidth === wrapper.clientWidth) {
scrollRightBtn.style.display = 'none';
} else {
scrollRightBtn.style.display = 'block';
}
});
}
// Прослушиваю прокрутку в таблице (в том числе и стандартными свойствами браузера, не только моими кнопками)
function listenerScrollBarBrowserScrollTable(tableItem) {
const wrapper = tableItem.parentElement;
let last_known_scroll_position = 0;
let ticking = false;
function doSomething() {
manSingleScrollToggleBtn(tableItem);
}
wrapper.addEventListener('scroll', function (e) {
last_known_scroll_position = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(function () {
doSomething(last_known_scroll_position);
ticking = false;
});
ticking = true;
}
});
}
// Прослушиваю изменение ширины окна браузера
function listenerWindowResizeForTableScroll(tableItem) {
(function () {
const throttle = function (type, name, obj) {
obj = obj || window;
let running = false;
const func = function () {
if (running) {
return;
}
running = true;
requestAnimationFrame(function () {
obj.dispatchEvent(new CustomEvent(name));
running = false;
});
};
obj.addEventListener(type, func);
};
/* init - you can init any event */
throttle("resize", "optimizedResize");
})();
// handle event
window.addEventListener("optimizedResize", function () {
const wrapper = tableItem.parentElement;
const scrollRightBtn = tableItem.parentElement.querySelector('.arrow-right');
if (wrapper.scrollWidth === wrapper.clientWidth) {
scrollRightBtn.style.display = 'none';
} else {
scrollRightBtn.style.display = 'block';
}
});
}
// Прокручиваю таблицу при клике на кнопку прокрутки
function manSingleScrollBtnClick(e) {
const btn = e.currentTarget;
const table = btn.parentElement.querySelector('table');
const inner = table.parentElement;
if (btn.classList.contains('arrow-left')) {
inner.scrollLeft = inner.scrollLeft - 30;
}
if (btn.classList.contains('arrow-right')) {
inner.scrollLeft = inner.scrollLeft + 30;
}
// Отображаю и прячу кнопки прокрутки в процессе прокрутки
manSingleScrollToggleBtn(table);
}
// Отображаю и прячу кнопки прокрутки в процессе прокрутки
function manSingleScrollToggleBtn(table) {
const scrollLeftBtn = table.parentElement.querySelector('.arrow-left');
const scrollRightBtn = table.parentElement.querySelector('.arrow-right');
const inner = table.parentElement;
const right_width = inner.scrollWidth - inner.scrollLeft - inner.clientWidth;
if (right_width === 0) {
scrollRightBtn.style.display = 'none';
} else {
scrollRightBtn.style.display = 'block';
}
if (inner.scrollLeft === 0) {
scrollLeftBtn.style.display = 'none';
} else {
scrollLeftBtn.style.display = 'block';
}
}
// Данную функцию я обычно сохраняю в другой файл и отправляю в нее все, что должно запуститься в момент изменения размеров окна браузера.
// listenResizeBrowser(manTablesScrollInitAfterResizeBrowsr, initializedTables);
// Прослушиваю изменение ширины окна браузера
function listenResizeBrowser(startFunctionNameAfterResize, args = false) {
(function() {
const throttle = function(type, name, obj) {
obj = obj || window;
let running = false;
const func = function() {
if (running) { return; }
running = true;
requestAnimationFrame(function() {
obj.dispatchEvent(new CustomEvent(name));
running = false;
});
};
obj.addEventListener(type, func);
};
/* init - you can init any event */
throttle("resize", "optimizedResize");
})();
// handle event
window.addEventListener("optimizedResize", function() {
if (args !== false) {
startFunctionNameAfterResize(args);
} else {
startFunctionNameAfterResize();
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment