【问题标题】:prevent full page scrolling iOS防止整页滚动iOS
【发布时间】:2013-05-29 04:09:48
【问题描述】:

在 Mobile Safari 下,是否可以允许绝对定位的 div 在滚动到边缘时不让整个页面上下摆动(弹性滚动)?

这是我面临的问题的一个最小工作示例:

<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        #a, #b {
            position: absolute;
            top: 0;
            left: 0;
            height: 100%;
            padding: 10px;
            overflow: auto;
        }
        #a {
            width: 80px;
            background: #f00;
        }
        #b {
            background: #00f;
            left: 80px;
            width: 100%;
        }
    </style>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script>
        function pdcb(e) {
            e.preventDefault();
        }
        function npcb(e) {
            e.stopPropagation();
        }
        $(document).on('touchstart touchmove', pdcb).
                    on('touchstart touchmove', '.scrollable', npcb);
    </script>
</head>
<body>
    <div id="a" class="scrollable">
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
        This<br>
        should<br>
        be<br>
        scrollable<br>
        but<br>
        not<br>
        scroll<br>
        the<br>
        whole<br>
        page<br>
    </div>
    <div id="b">
        this should never scroll
    </div>
</body>
</html>

解决方案:

$(document).on('touchmove', function(e) {
    e.preventDefault();
}).ready(function() {
    $(".scrollable").on('touchstart', function(e) {
        this.allowUp = (this.scrollTop > 0);
        this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
        this.prevTop = null;
        this.prevBot = null;
        this.lastY = e.originalEvent.pageY;
    }).on('touchmove', function(e) {
        var event = e.originalEvent;
        var up = (event.pageY > this.lastY), down = !up;
        this.lastY = event.pageY;

        if ((up && this.allowUp) || (down && this.allowDown))
            event.stopPropagation();
        else
            event.preventDefault();
    });
});

【问题讨论】:

  • 不,不是重复的。拥有两个divs 会改变一切。
  • 人们将其标记为重复 - 这不是重复的问题 - 引用的问题仅涉及完全阻止 iOS 中的原生动量滚动 - 这个问题/解决方案是关于在特定 div 上启用动量滚动同时阻止滚动整个页面。对于具有许多固定位置元素的 Web 应用很有用。
  • 如果您希望它与动态添加的元素一起使用(例如在单页 JS 应用中),请将 $(".scrollable").on('touchstart', ...) 替换为 $(document.body).on('touchstart', '.scrollable', ...)。
  • 当您已经在 div 的顶部时,此代码将阻止向上滚动。如果你将它用于 iOS 应用程序,它可能会感觉很糟糕。解决方法是将可滚动元素向下滚动 1px,因此可以使用反弹效果向上滚动:$('.scrollable')[0].scrollTop = 1。您还可以处理结束滚动事件,并在 scrollTop 达到 0 时将其设置为 1,因此它永远不会被阻止向上滚动。
  • 确保将 -webkit-overflow-scrolling: touch 添加到 .scrollable 类的 CSS 声明中以获得漂亮的原生滚动。

标签: javascript html ios css mobile-safari


【解决方案1】:

最初的答案很棒,但我解决了一些缺陷:

  • 如果元素位于顶部或底部,则不会分别向上和向下滚动。
  • 如果元素是动态添加的,它将没有滚动处理程序。
  • 存在未使用的变量(prevTop、prevBot)

我的回答解决了这些问题。 (注意我使用.scroll-y,而不是.scrollable)

首先,添加这些 CSS 规则:

.scroll-y {
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch; /* nice webkit native scroll */
}

将.scroll-y 类添加到您想要滚动的任何元素中。

然后,在某处添加这个 JS:

// Disable scroll for the document, we'll handle it ourselves
$(document).on('touchmove', function(e) {
  e.preventDefault();
});

// Check if we should allow scrolling up or down
$(document.body).on("touchstart", ".scroll-y", function (e) {
  // If the element is scrollable (content overflows), then...
  if (this.scrollHeight !== this.clientHeight) {
    // If we're at the top, scroll down one pixel to allow scrolling up
    if (this.scrollTop === 0) {
      this.scrollTop = 1;
    }
    // If we're at the bottom, scroll up one pixel to allow scrolling down
    if (this.scrollTop === this.scrollHeight - this.clientHeight) {
      this.scrollTop = this.scrollHeight - this.clientHeight - 1;
    }
  }
  // Check if we can scroll
  this.allowUp = this.scrollTop > 0;
  this.allowDown = this.scrollTop < (this.scrollHeight - this.clientHeight);
  this.lastY = e.originalEvent.pageY;
});

$(document.body).on('touchmove', ".scroll-y", function(e) {
  var event = e.originalEvent;
  var up = event.pageY > this.lastY;
  var down = !up;
  this.lastY = event.pageY;

  if ((up && this.allowUp) || (down && this.allowDown)) {
    event.stopPropagation();
  } else {
    event.preventDefault();
  }
});

【讨论】:

  • 我希望我能再投票一百万次,我一直在寻找一个可行的解决方案,所以谢谢!
【解决方案2】:

虽然您没有触及 div 内容的边缘,但您需要允许原生 touchmove 事件在该元素上工作(以便它可以滚动),但您会想要 停止该事件从冒泡 DOM 使其不会触发页面正文上的滚动。

当你到达元素的边界时,你需要完全阻止原生动量滚动。

我为此使用的代码如下(向原作者道歉,这是改编自我过去在互联网上某处找到的有关该主题的教程...似乎找不到网址现在虽然):

elem 是你的 DOM 节点

elem.addEventListener('touchstart', function(event){
    this.allowUp = (this.scrollTop > 0);
    this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
    this.prevTop = null; this.prevBot = null;
    this.lastY = event.pageY;
});

elem.addEventListener('touchmove', function(event){
    var up = (event.pageY > this.lastY), down = !up;
    this.lastY = event.pageY;

    if ((up && this.allowUp) || (down && this.allowDown)) event.stopPropagation();
    else event.preventDefault();
});

我通常定义一个元素数组并循环遍历它们 - 将此代码迭代地应用于每个元素。

祝你好运,希望这会有所帮助。

【讨论】:

  • 我还假设您的 .scrollable 类使用 -webkit-overflow-scrolling: touch ?如果没有,它应该:)
  • 对于对格式感到困惑的人:原始发布者添加了一个“解决方案”部分,该部分采用此代码并实现它。它对我很有效。
  • 如果您将它用于动态应用程序,请记住在替换新元素时将事件侦听器重新绑定到新元素!我将 elem.addEventListener 替换为 jQuery 的 $(document.body).on("touchstart", ".scrollable", function () {...});
  • @micho 非常感谢,您的评论真的很有帮助!
【解决方案3】:

Aaron Gray 提供的笔记有帮助!

查看链接: http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="minimum-scale=1.0, width=device-width, maximum-scale=1.0, user-scalable=no, initial-scale=1">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <style>

        .page{
            font-size: 24px;
            overflow: scroll;
        }

        .menu{
            position: fixed;
            top: 0;
            bottom: 0;
            left: 0;
            width: 80%;
            background: gray;
            z-index: 1;
            font-size: 10px;
            overflow: scroll;
            /* uncomment to get smooth momentum scroll, but also a rubber band effect */
            /*-webkit-overflow-scrolling: touch;*/
        }

        .menu-item{
            padding: 10px;
            background: darkgray;
            font-size: 24px;
        }

    </style>
</head>

<body>

<div class="menu scrollable">
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
    <div class="menu-item">hello world</div>
</div>

<div class="page disable-scrolling">
    Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's
    standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make
    a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting,
    remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing
    Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions
    of Lorem Ipsum.
</div>

<script>


    document.ontouchmove = function ( event ) {

        var isTouchMoveAllowed = true, target = event.target;

        while ( target !== null ) {
            if ( target.classList && target.classList.contains( 'disable-scrolling' ) ) {
                isTouchMoveAllowed = false;
                break;
            }
            target = target.parentNode;
        }

        if ( !isTouchMoveAllowed ) {
            event.preventDefault();
        }

    };

    function removeIOSRubberEffect( element ) {

        element.addEventListener( "touchstart", function () {

            var top = element.scrollTop, totalScroll = element.scrollHeight, currentScroll = top + element.offsetHeight;

            if ( top === 0 ) {
                element.scrollTop = 1;
            } else if ( currentScroll === totalScroll ) {
                element.scrollTop = top - 1;
            }

        } );

    }

    removeIOSRubberEffect( document.querySelector( ".scrollable" ) );


</script>

</body>
</html>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-12
    相关资源
    最近更新 更多