2011-11-08 70 views
9

我正在創建一個全屏幕的Web應用程序,它將有一些模塊/小部件,使用新的iOS 5溢出:滾動功能。 我想要的是在滾動html/body(因爲它是全屏)時禁用「bouncy」效果,但只保留可滾動元素的效果。禁用彈性滾動只爲html,但維護元素溢出:滾動

平滑滾動元素的效果,我有:

html, body { overflow: hidden; } 

.scrollable { 
    overflow: scroll; 
    -webkit-overflow-scrolling: touch; 
} 

然後將下面的腳本,禁用觸摸滾動效果:

$(document).bind('touchmove', function (e) { 
    if (e.target === document.documentElement) { 
     e.preventDefault(); 
    } 
}); 

雖然這似乎並沒有在所有的工作,因爲當滾動元素到非常底端或頂部時,它也會滾動documentElement

有沒有什麼辦法只禁用身體HTML元素的效果?

這是如何影響功能的一個很好的例子:

http://dl.dropbox.com/u/1928164/ios5/index.html

+0

我不認爲你的事件處理程序會碰到preventDefault(),因爲target是觸發事件的元素,它永遠不會是document.documentElement()。所以你會看到和沒有事件處理程序一樣的行爲。 – ThinkingStiff

+0

這將是'currentTarget'恐怕。目標可以返回任何內容,你可能想嘗試;) – zanona

+0

currentTarget返回元素與監聽器,而不是拋出事件的元素。 – ThinkingStiff

回答

0

原來對我來說,唯一有效的解決方案是使用joelambert/ScrollFix腳本,工作非常出色沒有滯後,實際上我已經在我的一個項目中使用它了。

您還可以查看有關his blog post的更多詳細信息。 對不起,其他用戶回覆,但我真的沒有得到這些答案爲我工作。

2

這是不幸的-webkit-overflow-scrolling不處理這更好。您需要跟蹤y的位置才能使其工作。我將類scroll放在我想要在我的頁面上滾動的任何內容上,例如<ul>元素。圍繞<ul>圍繞<div>填充視口,使用overflow-y: auto。不要把overflowheight放在<ul>上。 <ul>將會像其內容一樣高,並且它實際上是滾動的<div>-webkit-overflow-scrolling是繼承的,因此儘可能將DOM放在你想要的位置。

演示:http://jsfiddle.net/ThinkingStiff/FDqH7/

腳本:

var swipeY = 0; 

function onTouchMove(event) { 

    var scroll = event.target.closestByClassName('scroll'); 

    if (scroll) { 

     var top = scroll.positionTop - scroll.parentNode.positionTop, 
      heightDifference = (0 - scroll.offsetHeight + scroll.parentNode.offsetHeight); 

     if((top >= 0) && (event.touches[0].screenY > swipeY)) { 
      event.preventDefault(); //at top, swiping down 
     } else if((top <= heightDifference) && (event.touches[0].screenY < swipeY)) { 
      event.preventDefault(); //at bottom, swiping up 
     }; 

    } else { 
     event.preventDefault(); 
    }; 

}; 

function onTouchStart(event) { 

    swipeY = event.touches[0].screenY; 

}; 

Element.prototype.closestByClassName = function (className) { 

    return this.className && this.className.split(' ').indexOf(className) > -1 
     ? this 
     : (this.parentNode.closestByClassName && this.parentNode.closestByClassName(className)); 

}; 

window.Object.defineProperty(Element.prototype, 'positionTop', { 

    get: function() { 
     return this.offsetTop - this.parentNode.scrollTop; 
    } 

}); 

document.getElementById('viewport').addEventListener('touchmove', onTouchMove, false); 
document.getElementById('viewport').addEventListener('touchstart', onTouchStart, false); 

HTML:

<div id="viewport"> 
<div id="scroll-view"> 
    <ul class="scroll"> 
     <li>scroll scroll scroll scroll scroll </li> 
     <li>scroll scroll scroll scroll scroll </li> 
     <li>scroll scroll scroll scroll scroll </li> 

     . . . 

    </ul> 
</div> 
</div> 

CSS:

#viewport { 
    border: 1px solid black; 
    height: 460px; 
    width: 320px; 
    -webkit-overflow-scrolling: touch; 
} 

#scroll-view { 
    height: 100%; 
    overflow-y: auto; 
    width: 100%; 
} 
+0

我試過你的代碼用'#viewport'作爲aboslute定位了div,內含'overflow:auto'和大量的_lorem ipsun inside_,目前發生的事情是該腳本禁用了'viewport'的滾動,同時使得彈性滾動在主體中。 – zanona

+0

把一個div放在#viewport裏面,並把文本放在裏面。如果你使用上面的代碼,不要在內部div上設置溢出,但是在其上放置一個「滾動」類。 #viewport的巡視設置對於溢出和位置是正確的。 – ThinkingStiff

+0

@ludicco我更新了我的答案並創建了一個演示,使其更加清晰。我已經成功使用了幾個月了。 – ThinkingStiff

2

這裏有一個類似的答案ThinkingStiff的,不同的是它不要求你的html結構。它會查找已溢出內容的任何元素,並僅在用戶與其進行交互時才能進行滾動。

缺點:

  • 一旦用戶按下滾動節點的頂部或底部的限制,該節點內彈跳將不會發生(但它會如果從下面輕彈/上面的限制)。這可能意味着它不能滿足您的更新要求:

  • 在計算滾動偏移量時,我在測試用例中發現了一個奇怪的2px差異。不知道哪裏是來自,你可能需要調整值

的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

哇,那是哪種語言? – Bergi

+0

CoffeeScript(它編譯爲JavaScript - 它只是寫得更方便):http://coffeescript.org/ – Nevir

+0

是的,但突出顯示不支持如此之好... – Bergi