18

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

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

然而,触摸事件只会在 touchmove 期间可靠地固定菜单。如果我通过向上或向下滑动来快速滚动,则在菜单变为固定或不固定之前会有延迟。

有想法该怎么解决这个吗?在此处查看代码示例:http: //dev.driz.co.uk/mobileMasthead.html(已根据下面的一些答案进行了修改,但在 iPad 或 iPhone 上仍然无法正常工作)

更新: 阅读该主题表明,在滚动期间不会发生像检查滚动位置这样的 JS……但是……我注意到http://www.facebook.com/home/没有在我的 iPad 上测试时出现此问题。因此,绝对可以在不使用任何自定义 JavaScript 滚动条(如 iScroll 或类似内容)的情况下实现此效果。

4

9 回答 9

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

您可以在此处查看一个工作示例。

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

新学校(花哨但缓慢)

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

但请注意,众所周知,JavaScript 与移动设备上的滚动结合使用会在速度方面造成很多麻烦。

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

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

于 2013-07-05T23:21:39.243 回答
5

Facebook 不使用 JavaScript,而是使用纯 CSS:

position: -webkit-sticky;

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

于 2013-07-01T17:13:52.253 回答
2

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

首先也是最重要的是,scroll事件在移动设备上触发的频率不如在桌面上触发的频率高。通常它会在页面停止时触发。我不知道确切的原因,但我可以建议这是因为移动设备上的浏览器将此类任务“发送”到 GPU 同时 CPU 无法使 JS 对象与画布上发生的情况保持同步(但这只是我的建议)。更新版本的 iOS 让我们变得更好,并且可能scroll会在 iPhone 上运行。

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

touch事件也很棘手,尤其是在 Android 上。我认为在touchmove事件的回调中我将能够找出当前坐标并从那一点走得更远。

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

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

http://jsbin.com/elaker/23

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

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

于 2013-07-06T23:58:14.633 回答
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/

于 2013-07-05T21:01:08.690 回答
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";
    }
},
于 2013-07-02T12:19:03.933 回答
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 和推特: http ://ejohn.org/blog/learning-from-twitter/

希望对 Ajios 有所帮助!

于 2013-06-26T11:04:51.643 回答
1

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

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

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

于 2013-07-02T18:13:28.493 回答
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 中。

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

于 2013-07-02T18:28:04.993 回答
1

您是否需要触摸事件来触发它?现代设备应该返回$(window).scroll()事件和scrollTop值。在较旧的 Android 和 ios5 之前的版本(我认为)上,position:fixed:由于视口的工作方式,没有按预期工作。但它已在所有新版本中得到纠正。

要进一步调试设备,我强烈推荐 Adob​​e Edge Inspect。您可以console.log使用 scrollTop 并查看您关心的设备是否确实可以正常工作而没有任何欺骗。您将通过他们的免费版本获得所需的一切。

于 2013-06-21T17:55:10.607 回答