Как эмулировать прокрутку элемента?
Необходимо чтобы при попытке прокрутки одного элемента прокручивался другой. Причём, способ c onWheel+scrollTop не подходит, так как прокрутка получается резкой, неестественной. И никакой behavior: smooth это не исправляет (да, прокрутка становится плавной, но ещё менее естественной). Неужели нельзя никак "перенаправить" событие..?
Простейший пример:
const myWheel = (e) => {
document.getElementById('elem2').scrollTop += e.deltaY
document.getElementById('elem3').scrollTop += e.deltaY
}
document.getElementById('elem1').addEventListener("wheel", myWheel)
.elems {
display: flex;
}
.elems > div {
width: 100px;
height: 100px;
overflow-y: scroll;
}
#elem3 {scroll-behavior: smooth}
<div class='elems'>
<div id='elem1' style='background: pink'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
<div id='elem2' style='background: lightblue'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
<div id='elem3' style='background: lightgreen'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
</div>
Ответы (3 шт):
Полагаю все ваши попытки обречены на провал, так как существуют браузеры в которых реализован асинхронный скроллинг, и любые попытки идеально синхронизировать скролинг двух различных элементов посредством событийной модели будут неудачны.
Если нужно синхронизировать именно позицию ползунка прокрутки, то взгляните на решение ниже. Тем не менее учтите, в браузерах с асинхронным скроллингом данное решение будет работать рывками.
var el1 = document.getElementById('elem1'),
el2 = document.getElementById('elem2'),
el3 = document.getElementById('elem3');
const onScroll = (e) => {
el2.scrollTop = e.target.scrollTop;
el3.scrollTop = e.target.scrollTop;
};
el1.addEventListener("scroll", onScroll)
.elems {
display: flex;
}
.elems > div {
width: 100px;
height: 100px;
overflow-y: scroll;
}
#elem3 {
/* scroll-behavior: smooth */
}
<div class='elems'>
<div id='elem1' style='background: pink'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
<div id='elem2' style='background: lightblue'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
<div id='elem3' style='background: lightgreen'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
</div>
Чтобы прокрутка оставалась плавной, надо присваивать scrollTop для всех элементов кроме того, который скроллит пользователь. И надо использовать нормальное событие scroll, а не какие-то мышиные аналоги. В IE останется проблема с синхронизацией во время скролла, в Chrome всё будет идеально, в FF достаточно хорошо. Улцчшить не удалось.
var last = 0;
document.body.addEventListener('scroll', function (event) {
var st = event.target.scrollTop;
if (st !== last) {
last = st;
var divs = document.querySelectorAll('div');
for (var q=0; q<divs.length; ++q) {
if (divs[q] !== event.target) {
divs[q].scrollTop = st;
}
}
}
}, true);
html, body, div {
height: 100%;
margin: 0;
}
div {
float: left;
width: 50%;
overflow: auto;
direction: ltr;
}
div:first-child {
direction: rtl;
}
div:before {
content: "";
display: block;
height: 10000px;
background: repeating-linear-gradient(to bottom, white 0, white 29px, black 30px);
}
<div></div>
<div></div>
Первый элемент не прокручивается, при скролле над ним прокручиваются два другие:
var container = document.querySelector('.elems');
var pos, skip, timer
reset();
function reset() {
skip = true
pos = container.scrollTop = 500;
skip = false
}
container.addEventListener('scroll', function (event) {
if (skip || event.target !== container) return
var st = container.scrollTop, diff = st - pos
pos = st;
var divs = container.children, i = 1, sts = Array(i);
for (var q=i; q<divs.length; ++q) {
sts.push(divs[q].scrollTop + diff);
}
for (var q=i; q<divs.length; ++q) {
divs[q].scrollTop = sts[q];
}
clearTimeout(timer)
timer = setTimeout(reset, 1000)
});
main {
display: inline-block;
overflow: hidden;
}
.elems {
display: flex;
height: 100px;
overflow-y: scroll;
margin-right: -17px;
}
.elems > div {
position: sticky;
top: 0;
width: 100px;
overflow-y: scroll;
}
.elems > div:first-child {
pointer-events: none;
}
.elems::before {
content: "";
float: left;
height: 1000px;
}
<main>
<div class='elems'>
<div id='elem1' style='background: pink'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
<div id='elem2' style='background: lightblue'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
<div id='elem3' style='background: lightgreen'>
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
a<br/>b<br/>c<br/>d<br/>e<br/>f<br/>g<br/>h<br/>i<br/>j<br/>k
</div>
</div>
<main>