检查触摸设备上的scrollTop

时间:2013-06-19 10:34:13

标签: javascript jquery touch

我有以下功能检查用户的滚动位置,以便菜单在滚过标头后固定

function checkScrolling() {
    if( $(window).scrollTop() > $('.masthead').height() ) { // we check against ACTUAL height
        $('.menu').addClass('fixed');
    }else {
        $('.menu').removeClass('fixed');
    }
}

这里是桌面和触摸屏事件监听器:

$(document).bind('touchstart touchend touchcancel touchleave touchmove', function(e){
    checkScrolling();
});

$(window).scroll(function(){
    checkScrolling();
});

然而,触摸事件仅在触摸时可靠地使菜单固定。如果我通过向上或向下滑动来快速滚动,则在菜单固定或不固定之前会有一段延迟。

有关如何解决此问题的任何想法? 请参阅此处的代码示例:http://dev.driz.co.uk/mobileMasthead.html(已根据以下某些答案进行了修改,但仍无法在iPad或iPhone上正常运行)

更新的 阅读主题可以看出JS在滚动过程中没有发生滚动位置...... 但是......我注意到http://www.facebook.com/home/没有这个问题在我的iPad上测试时。因此,在不使用任何自定义JavaScript滚动条(如iScroll或类似功能)的情况下实现此效果绝对是可能的。

9 个答案:

答案 0 :(得分:7)

也许我理解这个问题是错误的,但为了确保高速滚动的功能,你为什么不用纯CSS方式解决它(又称伪造'花式'效果):

旧学校(快速但原始)

<强> HTML

<div id="menu2"></div>
    <div class="scroll" id="scroller">
        <div id="overlay"></div>
        <div id="menu"></div>
    </div>

使用简单的CSS:

html, body { overflow: hidden; height: 100% }
body { margin:0; padding:0; }

 .scroll {
     -webkit-overflow-scrolling: touch;
     height:960px;
     width:640px;
 }

 #menu2 {
     width:640px;
     height:20px;
     background:red;
     position:absolute;
     z-index:-1;
 }

 #menu {
     width:100%;
     height:20px;
     background:red;
     z-index:0;
 }

您可以看到一个有效的例子HERE

这可能有点原始:但是嘿!有用! :)

新学校(花哨但很慢)

检查提供的所有其他答案。

但请注意,“已知'将JavaScript与移动设备上的滚动结合使用会对速度带来很多麻烦。

这就是为什么我认为简单的CSS方法可能会更好。

如果您想了解JavaScript和在移动设备上滚动(以及其他功能),那么我强烈推荐阅读两篇文章:

答案 1 :(得分:5)

Facebook不使用JavaScript而是纯css:

position: -webkit-sticky;

如果我没记错,这会使元素在滚动时粘在其父容器的顶部。

答案 2 :(得分:2)

您只需将滚动事件附加到窗口,文档或正文,而不是附加到自定义容器。

在iOS上,您无法在这些硬件加速的窗口滚动行为中以编程方式做出反应。

这是一个小提琴: 包装器:

<div id="content">

一些不那么相关的CSS:

html,body,#content {
    width:100%;
    height:100%;
}
#content {
    background-color: lightblue;
    overflow:scroll;
}

将侦听器附加到容器:

function checkScrolling() {
    if ($('#content').scrollTop() > mastheadHeight) {
        menu.addClass('fixed');
    } else {
        menu.removeClass('fixed');
    }
}

$('#content').scroll(function () {
    checkScrolling();
});

你可以在这里看到它只适用于JS的后备:

http://jsfiddle.net/jaibuu/YqPzS/

直接网址:http://fiddle.jshell.net/jaibuu/YqPzS/show/

答案 3 :(得分:2)

我曾尝试在网站的移动版本上实现粘性标头,但遇到了一系列问题。

首先也是最重要的是scroll事件不会像在桌面上那样经常在移动设备上触发。通常它会在页面停止时触发。我不知道确切的原因,但我可以建议它是因为移动设备上的浏览器“发送”这样的任务到GPU同时CPU无法使JS对象与画布发生的事情保持同步(但这只是我的建议)。较新版本的iOS对我们来说更好,而scroll可能适用于iPhone。

您应该使用touch个事件。这使您可以为支持触摸输入的设备编写单独的代码版本。因此,必须寻找可靠的平台测试方法。

touch事件也很棘手,特别是在Android上。我认为在touchmove事件的回调中,我将能够找出当前的坐标,并从那一点开始。

但是在Android上有这个问题https://code.google.com/p/android/issues/detail?id=5491,总结touchmove在触摸操作的最开始时会触发一次或两次,并且不再触发。这使得它完全没用。人们建议使用preventDefault(),但你不能再使用它进行滚动。

所以我最终想到了使用CSS转换从头开始重新实现滚动。到目前为止,这是我的结果:

http://jsbin.com/elaker/23

在您的设备上打开该链接,在桌面上打开http://jsbin.com/elaker/23/edit:您将能够编辑代码并在您的设备上实时更新,非常方便。

注意: 我想警告你,这个CSS滚动的东西是原始的,并且有一些已知的问题尚未解决:就像你有时可以滚动超出顶部或底部边界,或者如果你只是触摸(不移动)它仍然会滚动。臭名昭着的URL栏也不会隐藏。所以有工作要做。

答案 4 :(得分:1)

你是否需要触摸事件才能解决这个问题?现代设备应返回$(window).scroll()个事件和scrollTop值。在较旧的Android和pre-ios5(我认为)上,position:fixed:没有按预期工作,因为视口的工作方式。但它已在所有新版本中得到纠正。

为了进一步调试设备,我强烈推荐使用Adobe Edge Inspect。您可以console.log使用scrollTop查看您关注的设备是否实际上正常工作而没有任何诡计。你将获得免费版本所需的一切。

答案 5 :(得分:1)

处理滚动事件的一个好方法是不将支票附加到滚动事件 需要大量资源,并且与旧版浏览器无法很好地协作。 幸运的是,如果你只是执行一个时间循环,你可以有更多的控制权。 代码看起来像这样: (它被推特使用)

var MyMenu = $('#menu'),
    didScroll = false;

$(window).scroll(function() {
    didScroll = true;
});

setInterval(function() {
    if ( didScroll ) {
        didScroll = false;
        //Do your check here
        checkScrolling();
    }
}, 180);

你应该把你的$('。masthead')。height()放在你的checkScrolling函数之外(在更高的范围内),因为这种操作占用了大量的资源并且总是要求jquery“选择你的元素”并计算其大小将最终使您的应用程序滞后:

  var headerHeight = $('.masthead').height()
  function checkScrolling()
  .....

最后,您可以更改间隔属性的值(现在它是180(稍微超过60hz - 。屏幕的刷新时间)您可以使此值更大,如果您希望您的应用程序更高性能但是不太准确)

感谢John Resig和twitter: http://ejohn.org/blog/learning-from-twitter/

希望有所帮助 Ajios!

答案 6 :(得分:1)

setScrollTop: function(inTop) {
    var top = Math.max(0,inTop);

    if (wm.isMobile) { // should always be true for touch events 
        top = Math.min(top, this.listNode.clientHeight - this.listNodeWrapper.clientHeight);

        if (dojo.isWebKit) {
            this.listNode.style.WebkitTransform = "translate(0,-" + top + "px)";
        } else if (dojo.isMoz) {
            this.listNode.style.MozTransform = "translate(0,-" + top + "px)";
        } else if (dojo.isOpera) {
            this.listNode.style.OTransform = "translate(0,-" + top + "px)";
        } else if (dojo.isIE) {
            this.listNode.style.MsTransform = "translate(0,-" + top + "px)";
        }
        this.listNode.style.transform = "translate(0,-" + top + "px)";
        this._scrollTop = top;
        this._onScroll();
    } else {
        this.listNode.scrollTop = top + "px";
    }
},

答案 7 :(得分:1)

我刚刚测试了你的功能以提高效率。你应该试试这个

function checkScrolling() {         
    if( $(window).scrollTop() > mastheadHeight )menu.css('position','fixed');
    else menu.css('position','');
}

这将减少addClass和RemoveClass的函数调用,您的执行时间将生效。如果您想减少更多的执行时间,那么最好使用纯JavaScript

答案 8 :(得分:1)

$(document).ready(function(){
     var p = $("#stop").offset().top;

    $(window).scroll(function(){
        if(p<$(window).scrollTop()){
            console.log("div reached");
            $("#stop").css({position:"fixed",top:0});
        }
        else{
            console.log("div out");
            $("#stop").css({position:"static"});
        }

    })
});

我认为这会对你有帮助。

jsfiddle.net中的总代码为here

我已经在http://alexw.me/ipad2/中使用在线ipad2模拟器 ipad测试了它,并且已经在那里工作了。所以,我认为它也适用于真正的ipad。