我正在尝试使用以下代码实现两个DIV
的同步滚动。
$(document).ready(function() {
$("#div1").scroll(function () {
$("#div2").scrollTop($("#div1").scrollTop());
});
$("#div2").scroll(function () {
$("#div1").scrollTop($("#div2").scrollTop());
});
});
#div1
和#div2
具有相同的内容但尺寸不同,比如说
#div1 {
height : 800px;
width: 600px;
}
#div1 {
height : 400px;
width: 200px;
}
使用此代码,我面临两个问题。
1)滚动没有很好地同步,因为div的大小不同。我知道,这是因为,我直接设置scrollTop
值。我需要找到滚动内容的百分比,并为另一个scrollTop
计算相应的div
值。我不确定,如何找到实际的高度和当前滚动位置。
2)此问题仅在firefox
中找到。在Firefox中,滚动不像其他浏览器那样流畅。我认为这是因为上面的代码创建了一个无限循环的滚动事件。
我不确定,为什么这只发生在firefox上。有没有办法找到滚动事件的来源,以便我可以解决这个问题。
非常感谢任何帮助。
答案 0 :(得分:43)
您可以使用element.scrollTop / (element.scrollHeight - element.offsetHeight)
获取百分比(它将是0
和1
之间的值)。因此,您可以将其他元素的(.scrollHeight - .offsetHeight)
乘以此值进行比例滚动。
为避免在循环中触发侦听器,您可以暂时取消绑定侦听器,设置scrollTop
并重新绑定。
var $divs = $('#div1, #div2');
var sync = function(e){
var $other = $divs.not(this).off('scroll'), other = $other.get(0);
var percentage = this.scrollTop / (this.scrollHeight - this.offsetHeight);
other.scrollTop = percentage * (other.scrollHeight - other.offsetHeight);
// Firefox workaround. Rebinding without delay isn't enough.
setTimeout( function(){ $other.on('scroll', sync ); },10);
}
$divs.on( 'scroll', sync);
<强> http://jsfiddle.net/b75KZ/5/ 强>
答案 1 :(得分:3)
这就是我正在使用的。只需使用要同步的两个元素调用syncScroll(...)
函数即可。我发现pawel的解决方案在鼠标或触控板实际完成操作后继续慢慢滚动存在问题。
参见工作示例here。
// Sync up our elements.
syncScroll($('.scroll-elem-1'), $('.scroll-elem-2'));
/***
* Synchronize Scroll
* Synchronizes the vertical scrolling of two elements.
* The elements can have different content heights.
*
* @param $el1 {Object}
* Native DOM element or jQuery selector.
* First element to sync.
* @param $el2 {Object}
* Native DOM element or jQuery selector.
* Second element to sync.
*/
function syncScroll(el1, el2) {
var $el1 = $(el1);
var $el2 = $(el2);
// Lets us know when a scroll is organic
// or forced from the synced element.
var forcedScroll = false;
// Catch our elements' scroll events and
// syncronize the related element.
$el1.scroll(function() { performScroll($el1, $el2); });
$el2.scroll(function() { performScroll($el2, $el1); });
// Perform the scroll of the synced element
// based on the scrolled element.
function performScroll($scrolled, $toScroll) {
if (forcedScroll) return (forcedScroll = false);
var percent = ($scrolled.scrollTop() /
($scrolled[0].scrollHeight - $scrolled.outerHeight())) * 100;
setScrollTopFromPercent($toScroll, percent);
}
// Scroll to a position in the given
// element based on a percent.
function setScrollTopFromPercent($el, percent) {
var scrollTopPos = (percent / 100) *
($el[0].scrollHeight - $el.outerHeight());
forcedScroll = true;
$el.scrollTop(scrollTopPos);
}
}
答案 2 :(得分:2)
如果div的大小相同,那么下面的代码是一种同步滚动它们的简单方法:
scroll_all_blocks: function(e) {
var scrollLeft = $(e.target)[0].scrollLeft;
var len = $('.scroll_class').length;
for (var i = 0; i < len; i++)
{
$('.scroll_class')[i].scrollLeft = scrollLeft;
}
}
这里我使用水平滚动,但你可以在这里使用scrollTop。此函数调用div上的scroll
事件,因此e
可以访问事件对象。
其次,您可以简单地计算出相应大小的div的比率,以适用于此行$('.scroll_class')[i].scrollLeft = scrollLeft;
答案 3 :(得分:2)
像发条一样运行(见DEMO)
$(document).ready(function(){
var master = "div1"; // this is id div
var slave = "div2"; // this is other id div
var master_tmp;
var slave_tmp;
var timer;
var sync = function ()
{
if($(this).attr('id') == slave)
{
master_tmp = master;
slave_tmp = slave;
master = slave;
slave = master_tmp;
}
$("#" + slave).unbind("scroll");
var percentage = this.scrollTop / (this.scrollHeight - this.offsetHeight);
var x = percentage * ($("#" + slave).get(0).scrollHeight - $("#" + slave).get(0).offsetHeight);
$("#" + slave).scrollTop(x);
if(typeof(timer) !== 'undefind')
clearTimeout(timer);
timer = setTimeout(function(){ $("#" + slave).scroll(sync) }, 200)
}
$('#' + master + ', #' + slave).scroll(sync);
});
答案 4 :(得分:1)
我喜欢pawel的干净解决方案,但它缺少我需要的东西,并且有一个奇怪的滚动错误,它继续滚动,我的插件将在多个容器上工作而不仅仅是两个。
http://www.xtf.dk/2015/12/jquery-plugin-synchronize-scroll.html
示例&amp;演示:http://trunk.xtf.dk/Project/ScrollSync/
插件:http://trunk.xtf.dk/Project/ScrollSync/jquery.scrollSync.js
$(&#39; .scrollable&#39)。scrollSync();
答案 5 :(得分:1)
如果您不想要按比例滚动,而是在每个字段上滚动相等数量的像素,则可以将更改值添加到您将scroll-event绑定到的字段的当前值。
假设#left
是小字段,而#right
是较大的字段。
var oldRst = 0;
$('#right').on('scroll', function () {
l = $('#left');
var lst = l.scrollTop();
var rst = $(this).scrollTop();
l.scrollTop(lst+(rst-oldRst)); // <-- like this
oldRst = rst;
});
https://jsfiddle.net/vuvgc0a8/1/
通过添加更改值,而不只是将其设置为#right
的{{1}},您可以在小字段中向上或向下滚动,无论其scrollTop()
是什么不到更大的领域。这方面的一个例子是Facebook上的用户页面。
这是我来到这里时所需要的,所以我想我会分享。
答案 6 :(得分:0)
来自 pawel 解决方案(第一个答案)。
对于使用jQuery的 horizzontal synchronized scrolling ,这是解决方案:
var $divs = $('#div1, #div2'); //only 2 divs
var sync = function(e){
var $other = $divs.not(this).off('scroll');
var other = $other.get(0);
var percentage = this.scrollLeft / (this.scrollWidth - this.offsetWidth);
other.scrollLeft = percentage * (other.scrollWidth - other.offsetWidth);
setTimeout( function(){ $other.on('scroll', sync ); },10);
}
$divs.on('scroll', sync);
多个水平同步div的另一个解决方案就是这个,但它适用于宽度相同的div。
var $divs = $('#div1, #div2, #div3'); //multiple divs
var sync = function (e) {
var me = $(this);
var $other = $divs.not(me).off('scroll');
$divs.not(me).each(function (index) {
$(this).scrollLeft(me.scrollLeft());
});
setTimeout(function () {
$other.on('scroll', sync);
}, 10);
}
$divs.on('scroll', sync);
注意:仅适用于宽度相同的div
答案 7 :(得分:0)
我通过将滚动百分比设置为定点表示法percent.toFixed(0)
(参数为0)解决了同步滚动循环问题。这样可以防止两个同步元素之间不断变化的分数滚动高度不匹配,而这两个元素一直试图相互“追赶”。此代码将使它们最多只经过一个额外的步骤(即,在用户停止滚动后,第二个元素可能会继续滚动一个额外的像素)。这不是一个完美的解决方案,也不是最复杂的解决方案,但我当然可以找到最简单的解决方案。
var left = document.getElementById('left');
var right = document.getElementById('right');
var el2;
var percentage = function(el) { return (el.scrollTop / (el.scrollHeight - el.offsetHeight)) };
function syncScroll(el1) {
el1.getAttribute('id') === 'left' ? el2 = right : el2 = left;
el2.scrollTo( 0, (percentage(el1) * (el2.scrollHeight - el2.offsetHeight)).toFixed(0) ); // toFixed(0) prevents scrolling feedback loop
}
document.getElementById('left').addEventListener('scroll',function() {
syncScroll(this);
});
document.getElementById('right').addEventListener('scroll',function() {
syncScroll(this);
});