iOS的Safari浏览器 - 如何禁用反弹时,但允许滚动的div正常滚动?iOS的Safari浏览

2019-05-13 14:39发布

我工作的一个基于iPad上的Web应用程序,并需要防止滚动反弹,这样看起来不像一个网页。 我目前使用这种冻结视口并禁用反弹时:

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

这个伟大的工程来禁用反弹时,但我的应用程序有几个滚动的div,和上面的代码防止它们滚动

我针对的iOS 5及以上的只有如此,我喜欢避免哈克iScroll解决方案。 相反,我使用这个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的开头或结尾移动。 我想找到一种方法来禁用这一点。

Answer 1:

这解决了问题,当您滚过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没有溢出整个页面滚动这是不行的。 要阻止,使用下面的事件处理程序,而不是一个立即上述(改编自这个问题 ):

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


Answer 2:

利用泰勒道奇出色的答案一直落后于我的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修复了一些渲染毛刺( 来源 ):

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


Answer 3:

一是防止对整个文档照常默认操作:

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

然后传播到文档级别停止类元素。 这将停止其到达上述因而函数e.preventDefault()没有被启动:

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

这个系统似乎更自然,比计算上的所有移动触摸屏类较不密集。 使用。对(),而不是.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" />


Answer 4:

你可以再补充一点更多的逻辑到您的反弹时禁用代码,以确保有问题的有针对性的元素不是一个你想滚动? 事情是这样的:

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


Answer 5:

最好的解决办法是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> 



Answer 6:

检查是否想尝试向下滚动,然后阻止默认操作,以移动停止整个页面时可达滚动或底部时滚动的元素已经滚动到顶部。

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


Answer 7:

我一直在寻找一种方式来阻止所有体滚动时有带滚动区域(一个“购物车”弹下有您的购物车的滚动视图)的弹出。

我写了使用最少的JavaScript来只需拨动你的身体上的类“noscroll”当你有一个弹出式或DIV,你想滚动(而不是“反弹时”整个页面体)一个更为优雅的解决方案。

而桌面浏览器观察溢出:隐藏 - 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();
});


Answer 8:

我已经工作了一点workarround没有jQuery的。 不perfert但工作正常(尤其是如果你在一个scoll-Y滚动-X) https://github.com/pinadesign/overscroll/

下跌免费参与和改进



Answer 9:

此解决方案不要求你把一个滚动的类在您所有的滚动的div所以就比较一般了。 滚动被允许在其上,或者是孩子,INPUT元素contenteditables和溢出滚动或汽车的所有元素。

我使用自定义选择,我也缓存检查结果中的元素以提高性能。 没有必要每次都检查相同的元素。 这可能有一些问题,因为只有刚刚写好,但想我会分享。

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


Answer 10:

虽然禁用所有你需要的页面会造成问题,对其他滚动元素“touchmove”事件似乎是个好主意,因为很快。 最重要的是,如果你只(如果你想在网页为非滚动如身体)禁用某些元素“touchmove”事件,只要它启用了其他地方,IOS会导致铬势不可挡传播当URL酒吧切换。

虽然我无法解释这种行为,它看起来像防止的唯一途径似乎定身的位置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; )。 无需特殊班或其他任何东西。



Answer 11:

这里有一个仄兼容的解决方案

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


Answer 12:

这个工作对我来说(普通的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>


Answer 13:

试试这个它会工作完美。

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


Answer 14:

我曾用简单的令人惊讶的运气:

body {
    height: 100vh;
}

它的伟大工程,以禁用反弹时的弹出式窗口或菜单,并没有强制浏览器栏出现使用位置时,如:固定的。 但是 - 你需要保存滚动位置设置固定的高度之前和隐藏弹出时恢复它,否则,浏览器将滚动到顶部。



文章来源: iOS Safari – How to disable overscroll but allow scrollable divs to scroll normally?