Как синхронизировать смещение прокрутки двух элементов во время инерционной прокрутки

мне нужно сохранить смещение прокрутки элемента в синхронизации с другим (окно на самом деле), и у меня возникли проблемы с этим во время инерционного "отката" фазы прокрутки на мобильном Safari (iPad).

у меня есть несколько дивов с position:fixed; overflow:hidden и мне нужно сохранить их смещение прокрутки в синхронизации с окном (что означает прокрутку всего тела.) Обычно я бы закодировал его так (jQuery):

var $win = $(window),
    $div1 = $(...)

$win.scroll(function() { 
    $div1.scrollTop($win.scrollTop())
})

но тестируя интерфейс на iPad, я заметил, что div был не обновляется ни во время сенсорной фазы, когда вы перетаскиваете виртуальную страницу пальцем, ни во время инерционной фазы, когда вы отпускаете и страница замедляется до остановки.

я решил его для фазы перетаскивания, зарегистрировав обработчик для touchmove событие, а также scroll один.

но я не могу найти способ решить проблему для инерциальной фазы. Div остается неподвижным (и медленно выходит из синхронизации с остальной частью страницы), пока инерционное движение приходит к полной остановке, когда событие прокрутки, наконец, срабатывает и оно переходит в положение.

вот рабочая демонстрация.

попробуйте прокрутить его на iPad, чтобы увидеть проблему "инерциального ругательства". К сожалению, я не смог заставить его работать на jsFiddle из-за странного поведения iPad с прокруткой iframe.

если бы я мог просто запустить опрос на этом этапе, я мог бы сохранить видимость синхронизации между два элемента. Я пробовал с setTimeout, setInterval и requestAnimationFrame, но ни один из них не срабатывает во время фазы инерциальной прокрутки. Кажется, что все JavaScript останавливается на этом этапе.

вопросы:

  • есть ли какое-либо событие касания или прокрутки, запущенное во время фазы инерциальной прокрутки?
  • здесь любой способ запуска обратного вызова Javascript на этом этапе?
  • есть ли способ синхронизировать смещение прокрутки двух элементов (либо X, либо Y, а не оба) с использованием CSS или какой-либо другой технологии, кроме JS?

3 ответов


OldDrunkenSailor избил меня, чтобы предложить iScroll.

к сожалению, из коробки iScroll просто реплицирует ту же проблему, что и собственная инерционная прокрутка-во время инерциальной фазы нет обработки событий.

вот версия вашей демо с исправленной обезьяной iScroll, чтобы добавить пользовательское событие, которое срабатывает даже во время инерциальной стадии:https://dl.dropbox.com/u/15943645/scrollingdemo.html

отлично работает на моем 2nd gen iPad.

JS:

// Disable touch events
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);

// Patch iScroll for position change custom event
iScroll.prototype._oldPos = iScroll.prototype._pos;
iScroll.prototype._pos = function(x, y) {
    this._oldPos(x, y);
    if (this.options.onPositionChange) this.options.onPositionChange.call(this);
}

$(function() {
    var $win = $(window),
        $div_cols = $('#cols'),
        $div_rows = $('#rows'),
        $div_body = $('#body')

    // attach scrolling sync handler and execute it once
    function sync_scroll(e) {
        $div_cols.scrollLeft(0 - $div_body.position().left);
        $div_rows.scrollTop(0 - $div_body.position().top);

    }           

    // initialize iScroll on wrapper div, with position change handler
    var myScroll = new iScroll('iscroll_wrapper', {
        bounce: false,
        onPositionChange: sync_scroll
    });
})

CSS:

#iscroll_wrapper {
    position:absolute;
    z-index: 1;
    left: 168px; 
    top:77px; 
    bottom:0px; 
    right:0;
    overflow:auto;
}

#body {
    position:absolute;
    z-index: 1;
    width: 2046px; 
    height: 3376px;

}

обратите внимание, что только тело реагирует на события касания, но вы можете расширить технику до строк и cols divs для обратной связи.


iOS фактически замораживает манипуляцию DOM и Javascript во время инерционной прокрутки происходит. Вот простая демонстрация, которую я сделал, чтобы проиллюстрировать разницу между прокруткой в обычной среде рабочего стола против iPad:http://jsfiddle.net/notjoelshapiro/LUcR6/. В этом коде есть только этот JS:

var num = 0;
function updateNum(){
    num++;
    $('#awesomeDiv').text(num);
}
$(window).scroll(updateNum);

при прокрутке он увеличивает число и отображает его в нижней части страницы. Вы увидите, что номер прокрутки в нижней части экран увеличивается только тогда, когда инерционный свиток остановился. Если Javascript действовал в фоновом режиме, он не будет обновляться, пока прокрутка не закончится, но число должно быть увеличено выше.

Итак, чтобы ответить на ваши вопросы:

есть ли какое-либо событие касания или прокрутки, запущенное во время фазы инерциальной прокрутки?

отрицательно, ghostrider.

есть ли способ запустить обратный вызов Javascript во время эта фаза?

см. выше.

есть ли способ синхронизировать смещение прокрутки двух элементов (X или Y, а не обоих) с помощью CSS или какой-либо другой технологии, отличной от JS?

Не совсем уверен, что вы имеете в виду здесь, JS может сделать все математические расчеты, которые вам нужны, но это должно быть, когда инерционный свиток завершен. Честно говоря, это может быть симптомом tl;dr, так как я сейчас на работе.

вы смотрели iScroll библиотеки? Он имитирует интерциальную (или неинерциальную) прокрутку для сенсорных и неинерциальных сред и дает вам обратные вызовы JS во время / после "прокрутки" и "инерциальной прокрутки" и предоставляет много информации, которую вы можете использовать для расчета, где вы находитесь на странице.


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

http://jquerymobile.com/demos/1.0rc1/docs/api/events.html#/demos/1.0rc1/docs/api/events.html

вот что они говорят по разделу начать свиток