javascript 使用 jQuery 同步滚动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18952623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 13:49:29  来源:igfitidea点击:

Synchronized scrolling using jQuery?

javascriptjquerycssscroll

提问by Nauphal

I am trying to implement synchronized scrolling for two DIVwith the following code.

我正在尝试DIV使用以下代码为两个人实现同步滚动。

DEMO

演示

$(document).ready(function() {
    $("#div1").scroll(function () { 
        $("#div2").scrollTop($("#div1").scrollTop());
    });
    $("#div2").scroll(function () { 
        $("#div1").scrollTop($("#div2").scrollTop());
    });
});

#div1and #div2is having the very same content but different sizes, say

#div1并且#div2具有相同的内容但大小不同,例如

#div1 {
 height : 800px;
 width: 600px;
}
#div1 {
 height : 400px;
 width: 200px;
}

With this code, I am facing two issues.

使用此代码,我面临两个问题。

1) Scrolling is not well synchronized, since the divs are of different sizes. I know, this is because, I am directly setting the scrollTopvalue. I need to find the percentage of scrolled content and calculate corresponding scrollTopvalue for the other div. I am not sure, how to find the actual height and current scroll position.

1) 滚动不同步,因为 div 的大小不同。我知道,这是因为,我是直接设置scrollTop值的。我需要找到滚动内容的百分比并计算scrollTop其他div. 我不确定,如何找到实际高度和当前滚动位置。

2) This issue is only found in firefox. In firefox, scrolling is not smooth as in other browsers. I think this because the above code is creating a infinite loop of scroll events. I am not sure, why this is only happening with firefox. Is there any way to find the source of scroll event, so that I can resolve this issue.

2)此问题仅在firefox. 在 firefox 中,滚动不像其他浏览器那样流畅。我认为这是因为上面的代码正在创建滚动事件的无限循环。我不确定,为什么这只发生在 Firefox 上。有没有办法找到滚动事件的来源,以便我可以解决这个问题。

Any help would be greatly appreciated.

任何帮助将不胜感激。

回答by pawel

You can use element.scrollTop / (element.scrollHeight - element.offsetHeight)to get the percentage (it'll be a value between 0and 1). So you can multiply the other element's (.scrollHeight - .offsetHeight)by this value for proportional scrolling.

您可以使用element.scrollTop / (element.scrollHeight - element.offsetHeight)来获取百分比(它将是0和之间的值1)。因此,您可以将其他元素乘以(.scrollHeight - .offsetHeight)该值以进行比例滚动。

To avoid triggering the listeners in a loop you could temporarily unbind the listener, set the scrollTopand rebind again.

为避免在循环中触发侦听器,您可以暂时解除绑定侦听器,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/

http://jsfiddle.net/b75KZ/5/

回答by goozbox

This is what I'm using. Just call the syncScroll(...)function with the two elements you want to synchronize. I found pawel's solution had issues with continuing to slowly scroll after the mouse or trackpad was actually done with the operation.

这就是我正在使用的。只需syncScroll(...)使用要同步的两个元素调用该函数即可。我发现 pawel 的解决方案在鼠标或触控板实际完成操作后继续缓慢滚动存在问题。

See working example 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);
  }
}

回答by ktretyak

Runs like clockwork (see 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);

});

回答by Rahul Dole

If the divs are of equal sizes then this code below is a simple way to scroll them synchronously:

如果 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;
        }

    }

Here im using horizontal scroll, but you can use scrollTop here instead. This function is call on scrollevent on the div, so the ewill have access to the event object. Secondly, you can simply have the ratio of corresponding sizes of the divs calculated to apply in this line $('.scroll_class')[i].scrollLeft = scrollLeft;

我在这里使用水平滚动,但您可以在这里使用 scrollTop。此函数是scroll在 div上的事件上调用,因此e将可以访问事件对象。其次,您可以简单地计算在此行中应用的 div 的相应大小的比率$('.scroll_class')[i].scrollLeft = scrollLeft;

回答by Frost

I like pawel's clean solution but it lacks something I need and has a strange scrolling bug where it continues to scroll and my plugin will work on multiple containers not just two.

我喜欢 pawel 的干净解决方案,但它缺少我需要的东西,并且有一个奇怪的滚动错误,它会继续滚动,我的插件可以在多个容器上运行,而不仅仅是两个。

http://www.xtf.dk/2015/12/jquery-plugin-synchronize-scroll.html

http://www.xtf.dk/2015/12/jquery-plugin-synchronize-scroll.html

Example & demo: http://trunk.xtf.dk/Project/ScrollSync/

示例和演示:http: //trunk.xtf.dk/Project/ScrollSync/

Plugin: http://trunk.xtf.dk/Project/ScrollSync/jquery.scrollSync.js

插件:http: //trunk.xtf.dk/Project/ScrollSync/jquery.scrollSync.js

$('.scrollable').scrollSync();

$('.scrollable').scrollSync();

回答by Thorpentin

If you don't want proportional scrolling, but rather to scroll an equal amount of pixels on each field, you could add the value of change to the current value of the field you're binding the scroll-event to.

如果您不想按比例滚动,而是在每个字段上滚动等量的像素,则可以将更改的值添加到将滚动事件绑定到的字段的当前值。

Let's say that #leftis the small field, and #rightis the bigger field.

假设这#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/

https://jsfiddle.net/vuvgc0a8/1/

By adding the value of change, and not just setting it equal to #right's scrollTop(), you can scroll up or down in the small field, regardless of its scrollTop()being less than the bigger field. An example of this is a user page on Facebook.

通过添加 change 的值,而不仅仅是将其设置为等于#right's scrollTop(),您可以在小字段中向上或向下滚动,而不管它scrollTop()是否小于较大的字段。这方面的一个例子是 Facebook 上的用户页面。

This is what I needed when I came here, so I thought I'd share.

这是我来这里时所需要的,所以我想我会分享。

回答by gaspar_schott

I solved the sync scrolling loop problem by setting the scroll percentage to fixed-point notation: percent.toFixed(0), with 0 as the parameter. This prevents mismatched fractional scrolling heights between the two synced elements, which are constantly trying to "catch up" with each other. This code will let them catch up after at most a single extra step (i.e., the second element may continue to scroll an extra pixel after the user stops scrolling). Not a perfect solution or the most sophisticated, but certainly the simplest I could find.

我通过将滚动百分比设置为定点表示法解决了同步滚动循环问题: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);
});

回答by jafed

From the pawelsolution (first answer).

pawel解决方案(第一个答案)。

For the horizzontal synchronized scrollingusing jQuery this is the solution:

对于使用 jQuery的水平同步滚动,这是解决方案:

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);

JSFiddle

JSFiddle

An other solution for multiple horizontally synchronized divs is this, but it works for divs with same width.

多个水平同步 div 的另一种解决方案是 this,但它适用于具有相同宽度的 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);

NB: Only for divs with same width

注意:仅适用于具有相同宽度的 div

JSFiddle

JSFiddle