2011-12-22 106 views
7

iOS 5現在允許本機溢出:滾動支持。有條件地阻止移動Safari中的滾動/觸摸移動事件

我想要做的是禁用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> 

回答

-1

這裏有一個禁用垂直滾動所有(主要)工作的解決方案,但溢出的元素:

(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

在這個問題上沒有任何一個coffeescript標籤,也沒有人詢問咖啡標籤。 – 2012-11-23 10:25:25

+1

這是否使答案有效? – Nevir 2012-11-23 22:45:17

+10

是的,絕對。 – 2012-11-24 04:04:30

15

我知道你問這個問題已經有一段時間了,但是我遇到了同樣的問題,我用你的代碼作爲解決問題的基礎。所以謝謝你的靈感。

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

或者更簡潔,但最終的結果相同(信用Ĵ格里菲斯):

<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;" /> 
+6

如果(!$(e.target).closest('。scrollable'))表示handleMove函數的內容,那麼稍微簡潔一些的方法就是 。長度){ e.preventDefault(); }' – 2013-03-10 16:56:44

+0

@JGriffiths好的建議,我的意思是比這更早地更新這個答案,但現在已經這樣做了。謝謝 – Scott 2013-07-03 08:38:52

1

我想斯科特的答案,但它並沒有在我的iPhone的iOS工作5.1.1

而且,這個,如果你正在構建一個webClip應用就顯得尤爲重要,天哪,我真希望的iOS 6將允許一個視口標記,禁用自動反彈

我的版本下面的作品(或不),以及斯科特的回答上面,因爲它本質上是做同樣的事情。

的jQuery 1.7.2

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

如果你寫這篇文章的jQuery的document.ready事件會工作。基於Nevirs答案

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

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

我們可以使用touchstart事件,而不是touchmove事件。在一個手指事件下,它表示在平底鍋中不會發送任何事件,因此touchmove可能爲時已晚。

我將偵聽器添加到文檔,而不是正文。

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