2011-12-22 28 views
7

iOS 5 hiện cho phép tràn dữ liệu gốc: hỗ trợ cuộn.Điều kiện chặn sự kiện di chuyển/touchmove trong safari di động

Điều tôi muốn làm là tắt sự kiện touchmove cho mọi thứ trừ các thành phần có lớp 'có thể cuộn' hoặc con của họ.

Nhưng tôi dường như không làm cho nó hoạt động; đây là những gì tôi đã làm việc với bên dưới:

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

Trả lời

-1

Dưới đây là một giải pháp (chủ yếu) làm việc cho việc vô hiệu hóa di chuyển dọc cho tất cả nhưng tràn yếu tố sau:

(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

Không có thẻ coffeescript nào ở bất kỳ nơi nào trong câu hỏi này cũng như không ai hỏi về coffeescript. –

+1

Điều đó có làm cho câu trả lời kém hiệu quả hơn không? – Nevir

+10

Vâng, tuyệt đối. –

15

Tôi biết nó đã được một thời gian kể từ khi bạn hỏi câu hỏi, nhưng tôi đã có cùng một vấn đề và tôi đã sử dụng mã của bạn như là cơ sở để giải quyết vấn đề. Cảm ơn vì nguồn cảm hứng.

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

Hoặc ít tiết, nhưng cuối cùng kết quả tương tự (tín dụng J Griffiths):

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

Bạn cũng nên bao gồm thẻ META sau.

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

Một cách ngắn gọn hơn một chút để thể hiện nội dung của hàm handleMove sẽ là 'if (! $ (E.target) .closest ('. Scrollable').độ dài) { e.preventDefault(); } ' –

+0

@JGriffiths Đề xuất hay, tôi muốn cập nhật câu trả lời này sớm hơn điều này, nhưng đã làm như vậy ngay bây giờ. Cảm ơn – Scott

1

Tôi cố gắng trả lời của Scott nhưng nó đã không làm việc trên iphone của tôi iOS 5.1.1

Ngoài ra, điều này đặc biệt quan trọng nếu bạn đang xây dựng một ứng dụng webClip, gosh tôi làm iOS 6 sẽ hy vọng cho phép thẻ khung nhìn tắt tự động trả lại

Phiên bản của tôi bên dưới hoạt động (hoặc không) cũng như câu trả lời của Scott ở trên, vì về bản chất nó cũng giống như vậy.

jQuery 1.7.2

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

Nếu bạn viết những dòng này trong trường hợp jquery document.ready nó sẽ làm việc.

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

phiên bản JavaScript dựa trên Nevirs câu trả lời:

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

Chúng ta có thể sử dụng các sự kiện touchstart thay vì touchmove sự kiện. Dưới sự kiện Finger One nó nói rằng không có sự kiện được gửi trong một chảo, do đó touchmove có thể là quá muộn.

Tôi đã thêm người nghe vào tài liệu chứ không phải nội dung.

document.ontouchstart = function(e){ 
    e.preventDefault(); 
} 
Các vấn đề liên quan