2012-04-19 138 views
92

我正在研究基於iPad的網絡應用程序,並且需要防止過度滾動,以使其看起來不像網頁。我目前使用這種凍結視口並禁用反彈時:iOS Safari - 如何禁用overscroll,但允許可滾動的div正常滾動?

document.body.addEventListener('touchmove',function(e){ 
     e.preventDefault(); 
    }); 

這個偉大的工程來禁用反彈時,但我的應用程序有幾個滾動的div,並上面的代碼防止它們滾動

我只針對iOS 5及以上版本,所以我避免了像iScroll這樣的hacky解決方案。相反,我使用這個CSS我可滾動的div:

.scrollable { 
    -webkit-overflow-scrolling: touch; 
    overflow-y:auto; 
} 

此作品,未經文檔反彈時劇本,但沒有解決的div滾動問題。

沒有一個jQuery插件,有沒有辦法使用反彈時修復,但免除我的$(「滾動」)的div?

編輯:

我發現的東西,是一個不錯的解決方案:

// Disable overscroll/viewport moving on everything but scrollable divs 
$('body').on('touchmove', function (e) { 
     if (!$('.scrollable').has($(e.target)).length) e.preventDefault(); 
}); 

當你滾過div的開頭或結尾的視域依然繼續。我想找到一種方法來禁用它。

+0

嘗試了你的最後一個也沒有工作要麼 – 2012-10-19 11:44:12

+0

我可以保持視口不移動,當你滾動過去的div的末尾,明確捕獲滾動div的父級滾動事件,而不是讓它實際上滾動。如果您使用jQuery Mobile的很有道理在頁面級別,像這樣做:。 $(「DIV [數據角色=‘頁面’]」)上(「滾動」,功能(E){É .preventDefault();}); – 2013-02-18 20:47:35

+0

https://github.com/lazd/iNoBounce創建奇蹟 – 2015-04-25 08:06:52

回答

7

您是否可以在您的overscroll禁用代碼中添加更多邏輯以確保問題中的目標元素不是您想要滾動的元素?事情是這樣的:

document.body.addEventListener('touchmove',function(e){ 
    if(!$(e.target).hasClass("scrollable")) { 
     e.preventDefault(); 
    } 
}); 
+3

謝謝...這似乎是_should_工作,但它不。另外,它不應該是「可滾動」,而不是「.scrollable」(點)? – Jeff 2012-05-08 19:18:29

+0

正確!修復它,謝謝。 – DeveloperJoe 2013-01-21 08:23:34

+1

它看起來像是最深的嵌套元素,接收觸摸事件,所以你可能需要檢查所有的父母,看看你是否在一個可滾動的div。 – 2013-02-18 05:02:57

5

檢查是否想嘗試向下滾動,然後阻止默認操作,以移動停止整個頁面時可達滾動或底部時滾動的元素已經滾動到頂部。

var touchStartEvent; 
$('.scrollable').on({ 
    touchstart: function(e) { 
     touchStartEvent = e; 
    }, 
    touchmove: function(e) { 
     if ((e.originalEvent.pageY > touchStartEvent.originalEvent.pageY && this.scrollTop == 0) || 
      (e.originalEvent.pageY < touchStartEvent.originalEvent.pageY && this.scrollTop + this.offsetHeight >= this.scrollHeight)) 
      e.preventDefault(); 
    } 
}); 
+1

嘗試了一個不工作 – 2012-10-19 11:40:40

+0

我不得不檢查e.originalEvent.touches [0] .pageY而不是e.originalEvent.pageY。它的工作,但只有當你已經在滾動div的末尾。當滾動正在進行時(例如,您的滾動速度非常快),一旦到達可滾動div的末端,它就不會停止。 – Sashwat 2013-08-21 15:57:08

83

當你滾過DIV

var selScrollable = '.scrollable'; 
// Uses document because document will be topmost level in bubbling 
$(document).on('touchmove',function(e){ 
    e.preventDefault(); 
}); 
// Uses body because jQuery on events are called off of the element they are 
// added to, so bubbling would not work if we used document instead. 
$('body').on('touchstart', selScrollable, function(e) { 
    if (e.currentTarget.scrollTop === 0) { 
    e.currentTarget.scrollTop = 1; 
    } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) { 
    e.currentTarget.scrollTop -= 1; 
    } 
}); 
// Stops preventDefault from being called on document if it sees a scrollable div 
$('body').on('touchmove', selScrollable, function(e) { 
    e.stopPropagation(); 
}); 

注意的開頭或結尾,如果你想阻止整個頁面滾動,當一個div沒有這不會工作,這樣就解決了問題溢出。要阻止,請使用以下事件處理程序,而不是一個正上方(改編自this question):

$('body').on('touchmove', selScrollable, function(e) { 
    // Only block default if internal div contents are large enough to scroll 
    // Warning: scrollHeight support is not universal. (https://stackoverflow.com/a/15033226/40352) 
    if($(this)[0].scrollHeight > $(this).innerHeight()) { 
     e.stopPropagation(); 
    } 
}); 
+0

如果可滾動區域內有iframe,並且用戶開始在該iframe上滾動,則這不起作用。有沒有解決方法? – Timo 2013-03-08 15:56:48

+2

工作得很好 - 這絕對比直接針對'.scrollable'更好(這是我最初嘗試解決這個問題的方法)。 如果你是一個JavaScript的noob,並希望簡單的代碼刪除這些處理程序的下面的處理程序,這兩條線對我來說很好! '$(文件).off( 'touchmove');' 和 '$( '身體')關( 'touchmove touchstart', '.scrollable');' – Devin 2013-08-06 22:47:31

+0

它的工作完美的我。非常感謝,你救了我幾個小時! – marcgg 2013-10-15 21:06:19

22

使用泰勒道奇的優秀answer一直落後於我的iPad,所以我加了一些限制代碼,現在它的相當光滑。有時在滾動時有一些最小的跳過。

// Uses document because document will be topmost level in bubbling 
$(document).on('touchmove',function(e){ 
    e.preventDefault(); 
}); 

var scrolling = false; 

// Uses body because jquery on events are called off of the element they are 
// added to, so bubbling would not work if we used document instead. 
$('body').on('touchstart','.scrollable',function(e) { 

    // Only execute the below code once at a time 
    if (!scrolling) { 
     scrolling = true; 
     if (e.currentTarget.scrollTop === 0) { 
      e.currentTarget.scrollTop = 1; 
     } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) { 
      e.currentTarget.scrollTop -= 1; 
     } 
     scrolling = false; 
    } 
}); 

// Prevents preventDefault from being called on document if it sees a scrollable div 
$('body').on('touchmove','.scrollable',function(e) { 
    e.stopPropagation(); 
}); 

而且,把下面的CSS修復了一些渲染毛刺(source):

.scrollable { 
    overflow: auto; 
    overflow-x: hidden; 
    -webkit-overflow-scrolling: touch; 
} 
.scrollable * { 
    -webkit-transform: translate3d(0,0,0); 
} 
+0

如果裏面有一個iframe可滾動區域和用戶開始滾動在該iframe。有沒有一種解決方法? – Timo 2013-03-08 15:57:41

+1

似乎工作完美的向後拖,拖,但向下也將移動Safari瀏覽器。 – Abadaba 2013-04-11 15:26:15

+1

一個真棒解決方案......多謝:) – 2014-04-23 09:03:22

0

這裏有一個仄兼容的解決方案

if (!$(e.target).hasClass('scrollable') && !$(e.target).closest('.scrollable').length > 0) { 
     console.log('prevented scroll'); 
     e.preventDefault(); 
     window.scroll(0,0); 
     return false; 
    } 
12

在整個文檔像往常一樣首先防止默認操作:

$(document).bind('touchmove', function(e){ 
    e.preventDefault();   
}); 

然後停止將您的元素類傳播到文檔級別。這將停止其到達上述因而函數e.preventDefault()不被啓動:

$('.scrollable').bind('touchmove', function(e){ 
    e.stopPropagation(); 
}); 

該系統似乎是更加自然和比計算上的所有移動觸摸屏類較不密集。動態生成的元素使用.on()而不是.bind()。

也可以考慮這些元標籤,以防止不幸的事情,從您在使用滾動DIV發生:

<meta content='True' name='HandheldFriendly' /> 
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0' name='viewport' /> 
<meta name="viewport" content="width=device-width" /> 
3

我已經工作了一點workarround沒有jQuery的。不perfert但工作正常(尤其是如果你有一個scoll-Y滾動-X)https://github.com/pinadesign/overscroll/

下跌免費參加,並提高其

+1

與傑夫有同樣的問題,嘗試每一個答案,你的工作。謝謝! – 2013-07-18 15:08:38

+0

只有當.scrollable div有足夠的內容導致溢出時,接受的答案才適用於我。如果沒有溢出,「反彈」效應仍然存在。然而,這完美的作品,謝謝! – 2013-10-14 15:11:56

4

我一直在尋找一種方式來阻止所有的身體滾動有一個時彈出一個可滾動區域(一個「購物車」彈出窗口,其中有一個可滾動的購物車視圖)。

我寫了一個非常優雅的解決方案,使用最小的javascript來切換類「noscroll」在你的身體上,當你想要滾動的彈出窗口或div(而不是「overscroll」整個頁面主體) 。

雖然桌面瀏覽器觀察到溢出:隱藏 - iOS似乎忽略了,除非您將位置設置爲固定......這會導致整個頁面變成一個奇怪的寬度,所以您必須手動設置位置和寬度爲好。使用這個CSS:

.noscroll { 
    overflow: hidden; 
    position: fixed; 
    top: 0; 
    left: 0; 
    width: 100%; 
} 

與這個jQuery:

/* fade in/out cart popup, add/remove .noscroll from body */ 
$('a.cart').click(function() { 
    $('nav > ul.cart').fadeToggle(100, 'linear'); 
    if ($('nav > ul.cart').is(":visible")) { 
     $('body').toggleClass('noscroll'); 
    } else { 
     $('body').removeClass('noscroll'); 
    } 
}); 

/* close all popup menus when you click the page... */ 
$('body').click(function() { 
    $('nav > ul').fadeOut(100, 'linear'); 
    $('body').removeClass('noscroll'); 
}); 

/* ... but prevent clicks in the popup from closing the popup */ 
$('nav > ul').click(function(event){ 
    event.stopPropagation(); 
}); 
+0

這是非常有用的,並且是一種最小的方法,正是我所需要的。將位置設置爲固定,頂部爲0;左:0;寬度:100%;是我失蹤的元素。這對於飛出菜單也很有用。 – bdanin 2015-04-07 12:24:11

0

這個工作對我來說(普通的JavaScript)

var fixScroll = function (className, border) { // className = class of scrollElement(s), border: borderTop + borderBottom, due to offsetHeight 
var reg = new RegExp(className,"i"); var off = +border + 1; 
function _testClass(e) { var o = e.target; while (!reg.test(o.className)) if (!o || o==document) return false; else o = o.parentNode; return o;} 
document.ontouchmove = function(e) { var o = _testClass(e); if (o) { e.stopPropagation(); if (o.scrollTop == 0) { o.scrollTop += 1; e.preventDefault();}}} 
document.ontouchstart = function(e) { var o = _testClass(e); if (o && o.scrollHeight >= o.scrollTop + o.offsetHeight - off) o.scrollTop -= off;} 
} 

fixScroll("fixscroll",2); // assuming I have a 1px border in my DIV 

HTML:

<div class="fixscroll" style="border:1px gray solid">content</div> 
1

這個解決方案沒有按不要求你在你所有的scrollab上放置一個可滾動的類所以更爲普遍。在INPUT元素contenteditables和overflow scroll或autos的所有元素或子元素上都允許滾動。

我使用自定義選擇器,並且還將檢查結果緩存在元素中以提高性能。無需每次都檢查相同的元素。這可能有幾個問題,因爲只是寫了,但我想分享。

$.expr[':'].scrollable = function(obj) { 
    var $el = $(obj); 
    var tagName = $el.prop("tagName"); 
    return (tagName !== 'BODY' && tagName !== 'HTML') && (tagName === 'INPUT' || $el.is("[contentEditable='true']") || $el.css("overflow").match(/auto|scroll/)); 
}; 
function preventBodyScroll() { 
    function isScrollAllowed($target) { 
     if ($target.data("isScrollAllowed") !== undefined) { 
      return $target.data("isScrollAllowed"); 
     } 
     var scrollAllowed = $target.closest(":scrollable").length > 0; 
     $target.data("isScrollAllowed",scrollAllowed); 
     return scrollAllowed; 
    } 
    $('body').bind('touchmove', function (ev) { 
     if (!isScrollAllowed($(ev.target))) { 
      ev.preventDefault(); 
     } 
    }); 
} 
0

試試這個它會工作完美。

$('body.overflow-hidden').delegate('#skrollr-body','touchmove',function(e){ 
    e.preventDefault(); 
    console.log('Stop skrollrbody'); 
}).delegate('.mfp-auto-cursor .mfp-content','touchmove',function(e){ 
    e.stopPropagation(); 
    console.log('Scroll scroll'); 
}); 
3

最好的解決辦法是CSS/HTML: 讓一個div爲包裝的元素,如果沒有它已經 ,並將其設置位置予以確定和溢出隱藏。可選,設置寬度和高度爲100%,如果你想讓它填滿整個屏幕並沒有什麼,但整個畫面

#wrapper{ 
 
    height: 100%; 
 
    width: 100%; 
 
    position: fixed; 
 
    overflow: hidden; 
 
}
<div id="wrapper"> 
 
    <p>All</p> 
 
    <p>Your</p> 
 
    <p>Elements</p> 
 
</div>

+0

優秀。我把''wrapper''改成''html,body''。 – commonpike 2017-01-25 19:33:09

+0

這是個好主意 – 2017-02-05 19:48:36

1

雖然禁用所有「touchmove」事件似乎是個好主意,只要你需要頁面上的其他可滾動元素,它會導致問題。最重要的是,如果您只在某些元素上禁用了「touchmove」事件(例如,如果您希望該頁面不可滾動,則爲body),只要在其他地方啓用該事件,IOS就會在Chrome中導致無法阻止的傳播酒吧切換。

雖然我無法解釋這種行爲,它看起來像防止的唯一途徑似乎身體的位置設置爲fixed。唯一的問題是你會失去文檔的位置 - 例如,這對於模態尤其惱人。解決這個問題是使用這些簡單的VanillaJS功能的一種方法:

function disableDocumentScrolling() { 
    if (document.documentElement.style.position != 'fixed') { 
     // Get the top vertical offset. 
     var topVerticalOffset = (typeof window.pageYOffset != 'undefined') ? 
      window.pageYOffset : (document.documentElement.scrollTop ? 
      document.documentElement.scrollTop : 0); 
     // Set the document to fixed position (this is the only way around IOS' overscroll "feature"). 
     document.documentElement.style.position = 'fixed'; 
     // Set back the offset position by user negative margin on the fixed document. 
     document.documentElement.style.marginTop = '-' + topVerticalOffset + 'px'; 
    } 
} 

function enableDocumentScrolling() { 
    if (document.documentElement.style.position == 'fixed') { 
     // Remove the fixed position on the document. 
     document.documentElement.style.position = null; 
     // Calculate back the original position of the non-fixed document. 
     var scrollPosition = -1 * parseFloat(document.documentElement.style.marginTop); 
     // Remove fixed document negative margin. 
     document.documentElement.style.marginTop = null; 
     // Scroll to the original position of the non-fixed document. 
     window.scrollTo(0, scrollPosition); 
    } 
} 

使用該解決方案,你可以有一個固定的文件,並在你的頁面可以通過使用簡單的CSS溢出任何其他元素(例如,overflow: scroll;)。無需特殊課程或其他任何東西。

0

我只好用簡單的令人驚訝的運氣:

body { 
    height: 100vh; 
} 

它的偉大工程,以禁用反彈時的彈出式窗口或菜單,並沒有強制瀏覽器欄出現使用位置時,如:固定的。但是 - 您需要在設置固定高度之前保存滾動位置,並在隱藏彈出窗口時將其恢復,否則,瀏覽器將滾動到頂部。