Conditionally block scrolling/touchmove event in mobile safari

后端 未结 6 1641
暗喜
暗喜 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: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()
    

提交回复
热议问题