In my page I have two tables of same width, and them both do horizontal scroll. I need to set both tables to the same position when each one scrolls.
Actually, my code is:
var scrollA = $('#scrollA'),
scrollB = $('#scrollB');
scrollA.on('scroll', function() {
scrollB[0].scrollLeft = scrollA[0].scrollLeft;
});
It works. The problem is that there are situations where the loaded data is big enough to slow the browser and the scroll event.
Then, I'm trying to improve the user experience in those situations.
I did this snippet where I try to use the __defineSetter__
function of Object
:
var elementA = { scrollLeft: 30 },
elementB = { scrollLeft: 30 };
elementA.__defineSetter__('scrollLeft', val => elementB.scrollLeft = val);
elementA.scrollLeft += 5;
console.log(elementA.scrollLeft + ' == ' + elementB.scrollLeft);
But as you can see running the snippet, it sets undefined
to elementA.scrollLeft
and NaN
to elementB.scrollLeft
.
I'd like some guidance here, thanks for your time.
Don't do it. Make it one table. Keep it simple. See example.
Scroll events can fire at a high rate, so you may get smoother scrolling by throttling the scroll event handler, as trincot said in his answer. You can throttle a function using
setTimeout
. When moving things on the screen or dealing with other visible effects, though, I preferrequestAnimationFrame
.requestAnimationFrame
runs the callback before the next repaint, so the browser can do some optimizations.This code will get you closer to the solution, it is based on this example from MDN:
You can use the timestamp passed to the callback to further debounce the synchronization, but you may end with a kinda sluggish scroll in the second table if you put too much delay.
Your call to
__defineSetter__
replaces the property scrollLeft with one with the same name, which means you cannot get to the original property any more. Once you have called__defineSetter__
, any reading of the property results inundefined
:Also, the browser does not change the scrollLeft value via an assignment as you would do in JavaScript, so the setter function will not be called during a scroll event. You can verify this by putting a
console.log
in the setter function: nothing is displayed when you scroll:For the above two reasons there is no hope you can capture scrolling changes using
__defineSetter__
. You need to listen to thescroll
event like you did first.You might get better results if you do the synchronisation asynchronously, and skip some of the updates when you have many scroll events occurring:
Now when the browser generates more than one scroll event instantly, the second one will pre-empty your scheduled update of
scrollB[0].scrollLeft
: theclearTimeout
will prevent that update from happening, and the next one is scheduled instead.You could play with the delay argument of
setTimeout
to find the right balance:Increasing the delay will prevent events from stacking up, and so scrollB will then synchronise in a more responsive way, but fewer updates will be made to scrollB's scrollLeft property, which can make it scroll less fluently.