【问题标题】:Conditionally block scrolling/touchmove event in mobile safari有条件地阻止移动 Safari 中的滚动/触摸移动事件
【发布时间】:2011-12-22 22:37:12
【问题描述】:

iOS 5 现在允许原生溢出:滚动支持。

我想做的是禁用 touchmove 事件,除了具有“可滚动”类的元素或其子元素之外的所有内容。

但我似乎无法让它工作;这是我一直在使用的以下内容:

<html>
<head>
<style>
.scrollable {
 height: 5em;
 overflow-y: scroll;
 -webkit-overflow-scrolling: touch;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>

// doesn't seem to work
var handleMove = function (e) {
  if (!$(e.target).parents().andSelf().hasClass('scrollable')) {
    e.preventDefault();
  }
};

document.addEventListener('touchmove', handleMove, true);

</script>
</head>
<body>
<div>
don't scroll if you drag here
</div>
<div class='scrollable'>
should be scrollable if you drag here
<ul>
<li>and here</li>
<li>and here</li>
<li>and here</li>
<li>and here</li>
<li>and here</li>
<li>and here</li>
<li>and here</li>
<li>and here</li>
</ul>
</div>
don't scroll if you drag here
</body>
</html>

【问题讨论】:

    标签: javascript jquery webkit cordova mobile-safari


    【解决方案1】:

    我知道你问这个问题已经有一段时间了,但我遇到了同样的问题,我使用你的代码作为解决问题的基础。所以谢谢你的灵感。

    (Javascript + jQuery)

    <script>
    var handleMove = function (e) {
        var scrollable = false;
        var items = $(e.target).parents();
        $(items).each(function(i,o) {
            if($(o).hasClass("scrollable")) {
                scrollable = true;
            }
        });
        if(!scrollable)
            e.preventDefault();
    };
    document.addEventListener('touchmove', handleMove, true);
    </script>
    

    或者不那么冗长,但最终结果相同(信用 J Griffiths):

    <script>
    var handleMove = function (e) {
        if($(e.target).closest('.scrollable').length == 0) { e.preventDefault(); }
    }
    document.addEventListener('touchmove', handleMove, true);
    </script>
    

    您还应该包含以下 META 标记。

    <meta name="viewport" content="width=device-width, initial-scale=1.0,
      maximum-scale=1.0, user-scalable=no;" />
    

    【讨论】:

    • 表达 handleMove 函数内容的更简洁的方式是if (!$(e.target).closest('.scrollable').length) { e.preventDefault(); }
    • @JGriffiths 好建议,我的意思是比这更早更新这个答案,但现在已经这样做了。谢谢
    【解决方案2】:

    基于 Nevirs 答案的 JavaScript 版本:

    var initialY = null;
    var nodeStack = [];
    var $window = $(window);
    
    $window.bind('touchstart', function(e) {
        initialY = e.originalEvent.pageY;
        nodeStack = $(e.target).parents().andSelf().filter(':not(body, html)').get().reverse();
        nodeStack = nodeStack.map(function(node) {
            return $(node);
        });
    });
    
    $window.bind('touchend touchcancel', function(e) {
        initialY = null;
        nodeStack = [];
    });
    
    $window.bind('touchmove', function(e) {
    
        if (!initialY) {
            e.preventDefault();
        }
    
        var direction = e.originalEvent.pageY - initialY;
    
        for (var i = 0; i < nodeStack.length; i +=1) {
            var $node = nodeStack[i];
            var nodeHeight = $node.height();
            var scrollHeight = $node[0].scrollHeight - 2;
            var nodeScrollTop = $node.scrollTop();
    
            if (scrollHeight > nodeHeight) {
                // the user is dragging the content up, and the element is already scrolled down a bit.
                var allowedUp = direction > 0 && nodeScrollTop > 0;
    
                // the user is dragging the content down, and the element is up a bit.
                var allowedDown = direction < 0 && nodeScrollTop < scrollHeight - nodeHeight;
    
                if (allowedUp || allowedDown) {
                    return;
                }
            }
        }
    
        // disable drag
        e.preventDefault();
    });
    

    【讨论】:

      【解决方案3】:

      如果您在 jquery document.ready 事件中编写它,它将起作用。

      $('body').on('touchmove', function (e) {
        if ($(e.target).closest("your_scrollable_div_selector").length == 0)
          e.preventDefault();
      });
      

      【讨论】:

        【解决方案4】:

        我尝试了 Scott 的回答,但它在我的 iphone iOS 5.1.1 上不起作用

        此外,如果您正在构建 webClip 应用程序,这一点尤其重要,天哪,我希望 iOS 6 将允许禁用自动反弹的视口标签

        我下面的版本和上面 Scott 的回答一样有效(或不有效),因为它基本上做同样的事情。

        jQuery 1.7.2

                $(document).bind("touchmove",function(e){
                    e.preventDefault();
                });
                $('.scrollable').bind("touchmove",function(e){
                    e.stopPropagation();
                });
        

        【讨论】:

          【解决方案5】:

          我们可以使用 touchstart 事件代替 touchmove 事件。在 One Finger Events 下,它表示在平移期间没有发送任何事件,因此 touchmove 可能为时已晚。

          我将侦听器添加到文档,而不是正文。

          document.ontouchstart = function(e){ 
            e.preventDefault(); 
          }
          

          【讨论】:

            【解决方案6】:

            这是一个(大部分)可行的解决方案,用于禁用所有但溢出的元素的垂直滚动:

            (CoffeeScript):

            # Vertical scrolling behavior overrides.
            #
            # This disables vertical scrolling on the page for touch devices, unless the user is scrolling
            # within an overflowed node.  This requires some finessing of the touch events.
            #
            # **NOTE:** This code ends up disabling bounce behavior if the user tries to scroll on a node that
            # is already at its upper or lower limit.
            window$   = $(window)
            initialY  = null
            nodeStack = []
            
            # When a user begins a (potential) drag, we jot down positional and node information.
            #
            # The assumption is that page content isn't going to move for the duration of the drag, and that
            # it would also be awkward if the drag were to change/stop part way through due to DOM
            # modifications.
            window$.bind 'touchstart', (evt) ->
              initialY  = evt.originalEvent.pageY
              nodeStack = $(evt.target).parents().andSelf().filter(':not(body, html)').get().reverse()
              nodeStack = nodeStack.map (node) -> $(node)
            
            window$.bind 'touchend touchcancel', (evt) ->
              initialY  = null
              nodeStack = []
            
            # We override the `touchmove` event so that we only allow scrolls in allowable directions,
            # depending on where the user first began the drag.
            window$.bind 'touchmove', (evt) ->
              return evt.preventDefault() if initialY == null
              # A positive direction indicates that the user is dragging their finger down, thus wanting the
              # content to scroll up.
              direction = evt.originalEvent.pageY - initialY
            
              for node$ in nodeStack
                nodeHeight    = node$.height()
                # For some reason, the node's scrollHeight is off by 2 pixels in all cases.  This may require
                # tweaking depending on your DOM.  Concerning.
                scrollHeight  = node$[0].scrollHeight - 2
                nodeScrollTop = node$.scrollTop()
            
                # If we have a scrollable element, we want to only allow drags under certain circumstances:
                if scrollHeight > nodeHeight
                  # * The user is dragging the content up, and the element is already scrolled down a bit.
                  return if direction > 0 and nodeScrollTop > 0
                  # * And the reverse: the user is dragging the content down, and the element is up a bit.
                  return if direction < 0 and nodeScrollTop < scrollHeight - nodeHeight
            
              # Otherwise, the default behavior is to disable dragging.
              evt.preventDefault()
            

            【讨论】:

            • 在这个问题上没有一个coffeescript标签,也没有人问过coffeescript。
            • 这是否会降低答案的有效性?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-21
            • 1970-01-01
            • 2020-12-09
            相关资源
            最近更新 更多