2013-09-23 5 views
21

Я пытаюсь реализовать синхронизированную прокрутку для двух DIV со следующим кодом.Синхронизированная прокрутка с помощью jQuery?

DEMO

$(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) Прокрутка не очень хорошо синхронизирована, так как divs имеют разные размеры. Я знаю, это потому, что я непосредственно устанавливаю значение scrollTop. Мне нужно найти процент прокрученного содержимого и рассчитать соответствующее значение scrollTop для другого div. Я не уверен, как найти фактическую высоту и текущую позицию прокрутки.

2) Этот вопрос встречается только в firefox. В firefox прокрутка не является гладкой, как в других браузерах. Я думаю, это потому, что приведенный выше код создает бесконечный цикл событий прокрутки. Я не уверен, почему это происходит только с firefox. Есть ли способ найти источник события прокрутки, чтобы я мог решить эту проблему.

Любая помощь была бы принята с благодарностью.

+0

несколько аналогичный вопрос и мой ответ: http://stackoverflow.com/a/15344759/2000060 – darshanags

ответ

42

Вы можете использовать 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/

+2

Вы также можете использовать плагин jQuery.throttle: https://github.com/cowboy/jquery-throttle-debounce – LeGEC

+2

Можно ли сделать div2 прокруткой горизонтально? – RafaSashi

+2

@RafaSashi конечно, просто измените '* Height' на' * Width' и '* Top' на' * Left' http: // jsfiddle.net/b75KZ/102/(редактирование: извините, я думал, что вы имеете в виду обе по горизонтали, но это должно быть так же просто, просто измените 'scrollLeft' на основе' scrollTop' и наоборот) – pawel

2

Если дивы имеют одинакового размера, то этот код ниже простой способ прокручивать их синхронно:

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. Эта функция вызывает событие scroll в div, поэтому e будет иметь доступ к объекту события. Во-вторых, вы можете просто иметь отношение соответствующих размеров разделов, рассчитанных для применения в этой строке $('.scroll_class')[i].scrollLeft = scrollLeft;

2

Это то, что я использую. Просто вызовите функцию 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

работает как часы (см 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); 

}); 
+0

Это отлично работает. Благодарю. – Garry

+0

Работает отлично, даже с колесиком мыши. –

0

С Pawel раствора (первый ответ).

Для horizzontal синхронизированных прокрутки с помощью 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

Другого решения для нескольких горизонтально синхронизированных дивов это, но это работает для дивы с одинаковой шириной.

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: Только для дивы с одинаковой шириной

JSFiddle

1

Мне нравится чистое решение Pawel, но ему не хватает что-то мне нужно, и имеет странную прокрутку ошибку, при которой она продолжает прокручивать и мои плагин будет работать на нескольких контейнерах не только двух.

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

Пример & демонстрационный: http://trunk.xtf.dk/Project/ScrollSync/

плагин: ('прокручиваемый'). http://trunk.xtf.dk/Project/ScrollSync/jquery.scrollSync.js

$ scrollSync();

+0

Это не работает в Edge. – HellBaby

+0

@Frost есть версия без jquery? – hipkiss

1

Если вы не хотите, пропорциональный скроллинга, а прокручивать равное количество пикселей на каждое поле, можно добавить величину изменения текущего значения поля вы связующую прокрутку-событие к.

Предположим, что #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 «s scrollTop(), вы можете прокручивать вверх или вниз в небольшом поле, независимо от его scrollTop() быть меньше, чем большее поле. Примером этого является страница пользователя на Facebook.

Это то, что мне было нужно, когда я приехал сюда, поэтому я решил поделиться с вами.

Смежные вопросы