在iPhone网页应用中禁用滚动?

60

有没有一种方法可以完全禁用 iPhone Web 应用程序中的网页滚动?我尝试了谷歌上发布的许多方法,但似乎都不起作用。

这是我的当前头部设置:

<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>

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

似乎不起作用。


kendall,您介意添加更多的代码,以便我可以看到输入了什么...我对此很新-以下是我拥有但不起作用的内容:<script language="javascript"> document.body.addEventListener('touchmove', function(e){ e.preventDefault(); }); document.body.addEventListener('touchstart', function(e){ e.preventDefault(); }); </script> - Andrew Samuelsen
4
没关系,我使用了这个代码:document.ontouchmove = function(e){ e.preventDefault(); } - Andrew Samuelsen
9个回答

58

改用touchstart事件替代touchmove。 根据单指事件的说明,在拖拽期间不会发送任何事件,因此touchmove可能太晚了。

我将监听器添加到文档而不是主体。

示例:

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

6
你实际上需要同时使用touchstart和touchmove,否则你仍然会出现滚动问题。 - Stefan Kendall
3
@jirapong,您能否添加更多的代码,以便我可以看到其中的问题...我对此还很陌生-这是我所拥有的并且不起作用的代码:<script language="javascript"> document.body.addEventListener('touchmove', function(e){ e.preventDefault(); }); document.body.addEventListener('touchstart', function(e){ e.preventDefault(); }); </script> - Andrew Samuelsen
2
@jirapong,谢谢。我用了这个:没关系,我用了这个:document.ontouchmove = function(e){ e.preventDefault(); } - Andrew Samuelsen
44
这也会屏蔽所有的轻触事件,因此页面上的任何内容都不能被轻触。 - keune
我曾在这里发布过类似的问题:http://stackoverflow.com/q/25016369/261375,截至2014年9月26日仍未得到回答。 - Ben
显示剩余6条评论

19
document.addEventListener('touchstart', function (e) {
    e.preventDefault();
});
不要使用ontouchmove属性注册事件处理程序,因为存在覆盖现有事件处理程序的风险。请改用addEventListener(请参阅MDN页面上关于IE的注意事项)。
请注意,防止在windowdocument上的touchstart事件的默认行为将禁用下层区域的滚动。
为了防止文档滚动但保留所有其他事件,请防止第一个touchmove事件跟随touchstart
var firstMove;

window.addEventListener('touchstart', function (e) {
    firstMove = true;
});

window.addEventListener('touchmove', function (e) {
    if (firstMove) {
        e.preventDefault();

        firstMove = false;
    }
});

这种方法有效的原因是移动版Safari使用第一次移动来确定是否正在滚动文档主体。在设计更复杂的解决方案时,我意识到了这一点。

如果这种方法以后不再有效,更复杂的解决方案是检查touchTarget元素及其父元素,并创建一个可以滚动到的方向映射。然后使用第一个touchmove事件来检测滚动方向,并查看它是要滚动文档还是目标元素(或目标元素的任何一个父元素):

var touchTarget,
    touchScreenX,
    touchScreenY,
    conditionParentUntilTrue,
    disableScroll,
    scrollMap;

conditionParentUntilTrue = function (element, condition) {
    var outcome;

    if (element === document.body) {
        return false;
    }

    outcome = condition(element);

    if (outcome) {
        return true;
    } else {
        return conditionParentUntilTrue(element.parentNode, condition);
    }
};

window.addEventListener('touchstart', function (e) {
    touchTarget = e.targetTouches[0].target;
    // a boolean map indicating if the element (or either of element parents, excluding the document.body) can be scrolled to the X direction.
    scrollMap = {}

    scrollMap.left = conditionParentUntilTrue(touchTarget, function (element) {
        return element.scrollLeft > 0;
    });

    scrollMap.top = conditionParentUntilTrue(touchTarget, function (element) {
        return element.scrollTop > 0;
    });

    scrollMap.right = conditionParentUntilTrue(touchTarget, function (element) {
        return element.scrollWidth > element.clientWidth &&
               element.scrollWidth - element.clientWidth > element.scrollLeft;
    });

    scrollMap.bottom =conditionParentUntilTrue(touchTarget, function (element) {
        return element.scrollHeight > element.clientHeight &&
               element.scrollHeight - element.clientHeight > element.scrollTop;
    });

    touchScreenX = e.targetTouches[0].screenX;
    touchScreenY = e.targetTouches[0].screenY;
    disableScroll = false;
});

window.addEventListener('touchmove', function (e) {
    var moveScreenX,
        moveScreenY;

    if (disableScroll) {
        e.preventDefault();

        return;
    }

    moveScreenX = e.targetTouches[0].screenX;
    moveScreenY = e.targetTouches[0].screenY;

    if (
        moveScreenX > touchScreenX && scrollMap.left ||
        moveScreenY < touchScreenY && scrollMap.bottom ||
        moveScreenX < touchScreenX && scrollMap.right ||
        moveScreenY > touchScreenY && scrollMap.top
    ) {
        // You are scrolling either the element or its parent.
        // This will not affect document.body scroll.
    } else {
        // This will affect document.body scroll.

        e.preventDefault();

        disableScroll = true;
    }
});

这个方法有效的原因是移动Safari使用第一个触摸移动事件来确定文档主体是否正在滚动,或者元素(或目标元素的任一父级)是否正在滚动,并坚持此决定。


您,值得一瓶啤酒! - Eirik Hoem
第二段代码片段对我来说完美运行。谢谢! - Peter
如果你能将它真正包装成一个可用的复制粘贴、随时可用的函数就好了。 - mjs
嗯,看起来它完全阻止了滚动,这意味着什么都不会滚动。 - TheBen
似乎firstmove方法在iOS 13上不再起作用了。现在所有元素都被阻止滚动。 - Damir

14

如果你正在使用 jQuery 1.7+,这个方法很有效:

$("donotscrollme").on("touchmove", false);

5
如果您已经完成了这个操作,有没有办法在“donotscrollme”子元素上启用滚动? - Pirkka Esko
2
好问题。你可以尝试 $("scrollme").on("touchmove", true); - 不确定是否有效。 - Rob Lauer
@Pirkka Esko - 你可以尝试 $(elem).removeClass('donotscrollme'); - Mladen Janjetovic
@PirkkaEsko 你可以尝试使用 $("parent child").on("touchmove", false); - Ralph David Abernathy

13

这应该可以正常工作了。顶部或底部不再有灰色区域:)

<script type="text/javascript">
   function blockMove() {
      event.preventDefault() ;
}
</script>

<body ontouchmove="blockMove()">

但这也会禁用任何可滚动区域。如果您想保留可滚动区域并仍然消除顶部和底部的橡皮筋效果,请参见此处:https://github.com/joelambert/ScrollFix


2
那个 bit.ly 的链接无法使用。你有原始的URL吗? - Bill the Lizard
1
链接为https://github.com/joelambert/ScrollFix。如果自定义域上的bit.ly链接停止工作,只需将域更改为bit.ly(此链接变为http://bit.ly/uaIgUn)。 - Lachlan Arthur

10

禁用:

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

启用:

document.ontouchstart = function(e){ return true; }

9

'self.webView.scrollView.bounces = NO;'这一行代码只需要在你的应用程序的mainViewController.m文件的'viewDidLoad'方法中添加即可。你可以在Xcode中打开它并添加它。

这样做可以使页面没有任何弹性反弹,同时仍然可以在应用程序视图中滚动。


已经有一段时间了,但是这个答案似乎并不适用于这个问题,因为它描述的是如何避免在本地iOS应用程序的scrollView中滚动。 - TheBen

4

该页面必须从主屏幕启动,才能使元标签生效。


2

我尝试了上面的答案,特别是Gajus的,但都没有起作用。最后我找到了下面的答案来解决这个问题,使得只有主体不滚动,而我的Web应用程序中的其他滚动部分都正常工作。 只需为您的body设置position fixed即可:

body {

height: 100%;
overflow: hidden;
width: 100%;
position: fixed;
}

这个很有效,特别是如果你在使用过程中从未更改它。如果这是你需要开关的东西,比如当模态框显示时,那么你可能需要考虑用户的滚动位置,因为每次都会被重置。对于一个大型电子商务网站,我使用了一个库:https://www.npmjs.com/package/body-scroll-lock - Kalnode

1
document.ontouchmove = function(e){ 
    e.preventDefault(); 
}

我发现实际上这是最好的选择,它允许您仍然能够点击输入字段以及使用jQuery UI draggable拖动物品,但它会阻止页面滚动。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接