如何在惯性滚动期间同步两个元素的滚动偏移 [英] How to synchronize the scroll offset of two elements during inertial scrolling

查看:161
本文介绍了如何在惯性滚动期间同步两个元素的滚动偏移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要保持元素的滚动偏移与另一个元素(实际上是窗口)保持同步,并且在移动Safari(iPad)上滚动的惯性滚动阶段我遇到了麻烦。

I need to keep the scroll offset of an element in sync with another (the window actually) and I'm having trouble doing so during the inertial "roll off" phase of scrolling on Mobile Safari (iPad).

我有几个div position:fixed; overflow:hidden 我需要保持他们的滚动偏移与窗口的一个同步(意味着整个身体滚动。)通常我会像这样(jQuery)编码:

I have a couple of divs with position:fixed; overflow:hidden and I need to keep their scroll offset in sync with the window's one (meaning the entire body scroll.) Usually I'd code it like this (jQuery):

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

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

但是在iPad上测试界面时,我注意到在触摸阶段,当你用手指拖动虚拟页面时,也没有在惯性阶段,当你放开,页面减速停止。

But testing the interface on an iPad, I noticed that the div was not being updated neither during the touch phase, when you are dragging the virtual page with your finger, nor during the inertial phase, when you let go and the page slows down to a stop.

我通过注册 touchmove 事件以及滚动一。

I solved it for the dragging phase by registering the handler for the touchmove event as well as the scroll one.

但是我找不到办法解决惯性阶段的问题。 div保持静止(并且慢慢地与页面的其余部分不同步)直到惯性运动达到完全停止,此时滚动事件最终被触发并且它跳到了位置。

But I can't find a way to solve the problem for the inertial phase. The div stays still (and goes slowly out of sync with the rest of the page) until the inertial movement comes to a full stop, when the scroll event is finally fired and it skips into position.

这是一个有效的演示。

尝试在iPad上滚动它以查看惯性晃动问题。不幸的是,我无法让它在jsFiddle上工作,因为iPad在iframe滚动时出现奇怪的行为。

Try to scroll it on an iPad to see the "inertial scolling" problem. Unfortunately I couldn't get it to work on jsFiddle, due to the iPad's weird behaviour with iframe scrolling.

如果我可以在那个阶段进行轮询,我可以保持两个元素之间的同步。我试过 setTimeout setInterval requestAnimationFrame ,但在惯性滚动阶段它们都没有发射。似乎所有Javascript都在此阶段停止。

If I could just run a polling during that phase, I could keep a semblance of synchronization between the two elements. I've tried with setTimeout, setInterval, and requestAnimationFrame, but neither of them fires during the inertial scrolling phase. It seems like all Javascript stops during that phase.

问题:


  • 是惯性滚动阶段会触发任何触摸或滚动事件吗?

  • 在该阶段是否有任何方式运行Javascript回调?

  • 有没有办法使用CSS或JS以外的其他技术同步两个元素(X或Y,而不是两者)的滚动偏移?

  • Is there any touch or scroll event fired during the inertial scrolling phase?
  • Is there any way to run a Javascript callback during that phase?
  • Is there a way to sync the scroll offset of two elements (either X or Y, not both) using CSS or some other technology other than JS?

推荐答案

OldDrunkenSailor打败我建议 iScroll

OldDrunkenSailor beat me to suggesting iScroll.

不幸的是,开箱即用的iScroll只是复制了与原生惯性滚动相同的问题 - 在惯性阶段没有事件处理。

Unfortunately, out of the box iScroll just replicates the same problem as native inertial scrolling -- there's no event handling during the inertial phase.

这是一个带有猴子修补的iScroll的演示版本,用于添加即使在惯性阶段也会触发的自定义事件: https://dl.dropbox.com/u/15943645/scrollingdemo.html

Here's a version of your demo with a monkey-patched iScroll to add a custom event that fires even during the inertial stage: https://dl.dropbox.com/u/15943645/scrollingdemo.html

在我的第二代iPad上运行良好。

Works great on my 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以获得反向关系。

Note only the body responds to touch events, but you can extend the technique to the rows and cols divs for the reverse relationship.

这篇关于如何在惯性滚动期间同步两个元素的滚动偏移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆