javascript 防止在移动浏览器上滚动,而不妨碍输入聚焦

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12485085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 16:17:19  来源:igfitidea点击:

Prevent scrolling on mobile browser, without preventing input focusing

javascriptandroidiosbrowserpreventdefault

提问by Bobby

I use preventDefault() on touchstart on the document to prevent scrolling on a page. Unfortunately this prevents too much. The user can no longer give focus to an input (and open the soft keyboard). Using jQuery focus(), I can give the focus to the input on a touchstart. This opens the soft keyboard on iOS (most of the time), but never on Android.

我在文档的 touchstart 上使用 preventDefault() 来防止在页面上滚动。不幸的是,这阻止了太多。用户不能再将焦点放在输入上(并打开软键盘)。使用 jQuery focus(),我可以将焦点放在 touchstart 上的输入上。这会在 iOS 上打开软键盘(大多数情况下),但不会在 Android 上打开。

Background:

背景

I have a webpage that I want to make as much like a mobile app as possible. I'm only really concerned with Android and iOS, but any form factor. I start by making the content in the page exactly the same size as the screen size. This is nice until the user puts their finger on the page. I need to prevent user scrolling. The following code accomplishes this, but in slightly different ways on the two operating systems.

我有一个网页,我想让它尽可能地像一个移动应用程序。我只真正关心 Android 和 iOS,但任何形式因素。我首先使页面中的内容与屏幕大小完全相同。这很好,直到用户将手指放在页面上。我需要防止用户滚动。以下代码实现了这一点,但在两个操作系统上的方式略有不同。

$(document).on('touchstart', function(e) {
    e.preventDefault();
});

On iOS, this prevents the elastic scrolling: where a user can reveal a texture behind the webpage by attempting to scroll off the page. The feature is nice for a regular webpage, but in my case it detracts from the UX.

在 iOS 上,这可以防止弹性滚动:用户可以通过尝试滚动页面来显示网页后面的纹理。该功能适用​​于常规网页,但就我而言,它有损于用户体验。

On Android, prevents the revelation of a handy hack that I use to hide the address bar. Android browsers start with the address bar visible, but as the user scrolls down the page, it disappears. To programmatically force the browser hide the address bar, simply add this line of code to your function called at load.

在 Android 上,阻止了我用来隐藏地址栏的一个方便的 hack 的启示。Android 浏览器开始时地址栏可见,但当用户向下滚动页面时,它就会消失。要以编程方式强制浏览器隐藏地址栏,只需将这行代码添加到加载时调用的函数中。

$('html, body').scrollTop(1);

This is a hacky (but also the only) way to tell the android browser that we have scrolled, and the address bar is no longer necessary.

这是告诉 android 浏览器我们已经滚动并且地址栏不再需要的一种hacky(但也是唯一的)方式。

Without the preventDefault on the document, the Android browser will allow scrolling and the address bar can be revealed.

如果文档上没有 preventDefault,Android 浏览器将允许滚动并显示地址栏。

So, both OS's have a good reason to have this preventDefault() called on every touchstart on the document, but it prevents too much. Tapping on an input field does nothing. Using a call to jQuery focus() can help, but only opens the soft keyboard on iOS, not Android.

因此,两个操作系统都有充分的理由在文档的每个 touchstart 上调用这个 preventDefault() ,但它阻止了太多。点击输入字段没有任何作用。使用对 jQuery focus() 的调用会有所帮助,但只能在 iOS 上打开软键盘,而不能在 Android 上打开。

$('input').on('touchstart', function() {
    $(this).focus();
});

How can I prevent the page from scrolling, but use the browser native functionality for giving focus to input fields?

如何防止页面滚动,但使用浏览器本机功能将焦点放在输入字段上?

Note: This code

注意:此代码

$(document).on('touchstart', function(e) {
    if (e.target.nodeName !== 'INPUT') {
        e.preventDefault();
    }
});

is flawed because the user can still scroll the page as long as the initial touch originates from within the input field.

是有缺陷的,因为只要初始触摸来自输入字段内,用户仍然可以滚动页面。

回答by Bobby

I actually solved this problem on another project, forgot about it, and remembered it most of the way through typing this up.

我实际上在另一个项目中解决了这个问题,忘记了它,并且通过输入它的大部分方式记住了它。

They key is to just do it on touchmove.

他们的关键是在 touchmove 上做。

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

However, preventDefault on touchstart does all kinds of nice things like preventing the image save menu on a gesture enabled slideshow. My projects also include this.

但是,touchstart 上的 preventDefault 做了各种好事,例如阻止启用手势的幻灯片上的图像保存菜单。我的项目也包括这个。

$(document).on('touchstart', function(e) {
    if (e.target.nodeName !== 'INPUT') {
        e.preventDefault();
    }
});

If anyone has some suggestions on additional content or how to reformat this so that it can reach a greater audience that would be great. I haven't ever seen the content I have here all in one place, so I felt that it needed to be on SO.

如果有人对其他内容或如何重新格式化内容有一些建议,以便它可以吸引更多的受众,那就太好了。我从来没有在一个地方看到我在这里的所有内容,所以我觉得它需要在 SO 上。

回答by Brian McCutchon

Combine the two!

两者结合!

// prevent scrolling from outside of input field
$(document).on('touchstart', function(e) {
    if (e.target.nodeName !== 'INPUT') {
        e.preventDefault();
    }
});

// prevent scrolling from within input field
$(document).on('touchmove', function(e) {
    if (e.target.nodeName == 'INPUT') {
        e.preventDefault();
    }
});

This probably isn't perfect either, and I am especially worried that the first function will prevent following links, but I'll leave it to others to do extensive tests.

这可能也不完美,我特别担心第一个功能会阻止以下链接,但我会将它留给其他人进行广泛的测试。

回答by tnt-rox

The simple answer to your question is don't use "preventDefault" instead use pointer-events css property to disable the scrolling on the element that scrolls.

您问题的简单答案是不要使用“preventDefault”,而是使用 pointer-events css 属性来禁用滚动元素的滚动。

CSS for your inputs:

用于输入的 CSS:

input {
    pointer-events: auto !important;
}

touchstart event listener:

触摸启动事件监听器:

document.body.addEventListener('touchstart', function(e) {
    if (e.target.nodeName === 'INPUT') {
        this.style.pointerEvents = 'none';
    }
});

You will need to reset the pointer-events when you blur the input.

当您模糊输入时,您将需要重置指针事件。

document.body.pointerEvents = 'auto';

+1 Good Question

+1 好问题