在我的页面中,我有两个相同宽度的表,它们都进行水平滚动。我需要在每个表滚动时将两个表设置为相同的位置。
实际上,我的代码是:
var scrollA = $('#scrollA'),
scrollB = $('#scrollB');
scrollA.on('scroll', function() {
scrollB[0].scrollLeft = scrollA[0].scrollLeft;
});
有效。问题是,在某些情况下,加载的数据足以使浏览器和滚动事件变慢。
然后,我正在尝试改善那些情况下的用户体验。
我在此片段中尝试使用__defineSetter__
的{{1}}函数:
Object
但是,正如您可以看到运行代码段一样,它会将var elementA = { scrollLeft: 30 },
elementB = { scrollLeft: 30 };
elementA.__defineSetter__('scrollLeft', val => elementB.scrollLeft = val);
elementA.scrollLeft += 5;
console.log(elementA.scrollLeft + ' == ' + elementB.scrollLeft);
设置为undefined
,将elementA.scrollLeft
设置为NaN
。
我想在这里给你一些指导,谢谢你的时间。
答案 0 :(得分:2)
您对__defineSetter__
的调用会将 scrollLeft 属性替换为 scrollLeft ,但这意味着您无法再访问原始属性。致电__defineSetter__
后,任何对该属性的阅读都会产生undefined
:
console.log(scrollA[0].scrollLeft); // some number, like 10
scrollA[0].__defineSetter__('scrollLeft', val => scrollB[0].scrollLeft = val)
console.log(scrollA[0].scrollLeft); // undefined
此外,浏览器不会像在JavaScript中那样通过赋值更改 scrollLeft 值,因此在滚动事件期间不会调用setter函数。您可以通过在setter函数中放置console.log
来验证这一点:滚动时不显示任何内容:
scrollA[0].__defineSetter__('scrollLeft', val => console.log(val))
由于上述两个原因,您无法使用__defineSetter__
捕获滚动更改。您需要像先前一样收听scroll
事件。
如果异步执行同步,可能会获得更好的结果,并在发生许多滚动事件时跳过某些更新:
var scrollA = $('#scrollA'),
scrollB = $('#scrollB'),
tmr = -1;
scrollA.on('scroll', function() {
clearTimeout(tmr);
tmr = setTimeout(_ => scrollB[0].scrollLeft = scrollA[0].scrollLeft, 0);
});
现在,当浏览器立即生成多个滚动事件时,第二个将预先清空您scrollB[0].scrollLeft
的预定更新:clearTimeout
将阻止更新发生,下一个是预定而来。
你可以使用setTimeout
的延迟参数来找到合适的平衡点:
增加延迟会阻止事件堆叠,因此 scrollB 将以更具响应性的方式进行同步,但对 scrollB的 的更新将会更少scrollLeft 属性,可以使它滚动得不那么流畅。
答案 1 :(得分:2)
滚动事件可以以高速率发射,因此您可以通过限制滚动事件处理程序来获得更顺畅的滚动,正如trincot在他的回答中所说的那样。您可以使用setTimeout
限制功能。但是,当在屏幕上移动内容或处理其他可见效果时,我更喜欢requestAnimationFrame
。
requestAnimationFrame
在下次重绘之前运行回调,因此浏览器可以进行一些优化。
此代码可让您更接近解决方案,它基于this example from MDN:
var scrollA = $('#scrollA'),
scrollB = $('#scrollB'),
running = false;
scrollA.on('scroll', function() {
// if we already requested an animation frame, do nothing
if (!running) {
window.requestAnimationFrame(function() {
// synchronize table B and table A
scrollB[0].scrollLeft = scrollA[0].scrollLeft
// we're done here and can request a new frame
running = false;
});
}
running = true;
});
您可以使用传递给回调的时间戳来进一步去抖动同步,但如果您放置太多延迟,则可能会在第二个表格中以某种缓慢的滚动结束。
答案 2 :(得分:0)
不要这样做。把它做成一张桌子。把事情简单化。见例。
<!DOCTYPE html>
<html>
<head>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 2000px;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
</style>
</head>
<body>
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
<tr>
<th>Ernst Handel</th>
<th>Roland Mendel</th>
<th>Austria</th>
</tr>
<tr>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
</tr>
</table>
</body>
</html>