Conditionally block scrolling/touchmove event in mobile safari

后端 未结 6 1540
暗喜
暗喜 2021-02-03 13:46

iOS 5 now allows native overflow: scroll support.

What I\'d like to do is disable the touchmove event for everything except elements that have the \'scrolla

相关标签:
6条回答
  • 2021-02-03 14:06

    JavaScript version based on Nevirs answer:

    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();
    });
    
    0 讨论(0)
  • 2021-02-03 14:11

    If you write this in jquery document.ready event it will work.

    $('body').on('touchmove', function (e) {
      if ($(e.target).closest("your_scrollable_div_selector").length == 0)
        e.preventDefault();
    });
    
    0 讨论(0)
  • 2021-02-03 14:18

    Here's a (mostly) working solution for disabling vertical scrolling for all but overflowed elements:

    (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()
    
    0 讨论(0)
  • 2021-02-03 14:23

    I know it's been a while since you asked the question, but I had the same issue and I used your code as the basis for solving the problem. So thanks for the inspiration.

    (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>
    

    Or less verbose, but ultimately the same result (credit J Griffiths):

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

    You should also include the following META tag.

    <meta name="viewport" content="width=device-width, initial-scale=1.0,
      maximum-scale=1.0, user-scalable=no;" />
    
    0 讨论(0)
  • 2021-02-03 14:28

    I tried Scott's answer but it didn't work on my iphone iOS 5.1.1

    Also, this is particularly important if you're building a webClip app, gosh I do hope iOS 6 will allow a viewport tag that disables the auto-bounce

    My version below works (or doesn't) as well as Scott's answer above, as it essentially does the same thing.

    jQuery 1.7.2

            $(document).bind("touchmove",function(e){
                e.preventDefault();
            });
            $('.scrollable').bind("touchmove",function(e){
                e.stopPropagation();
            });
    
    0 讨论(0)
  • 2021-02-03 14:30

    We can use the touchstart event instead of touchmove event. Under One Finger Events it says that no events are sent during a pan, so touchmove may be too late.

    I added the listener to document, not body.

    document.ontouchstart = function(e){ 
      e.preventDefault(); 
    }
    
    0 讨论(0)
提交回复
热议问题