禁用滚动条当切换 iPad 网页应用中的焦点元素

32

我有一个Web应用程序。我试图禁止/阻止在聚焦于不同表单输入时发生的滚动(即随着您在表单中向前移动到输入元素而发生的滚动)。

我已经使用以下方法禁用了滚动:

 <script type="text/javascript">
     $(document).ready(function() {
         document.ontouchmove = function(e){
              e.preventDefault();
              }
     });
 </script>
为了提供更多信息 - 我的页面由几个“幻灯片”组成。 每一个都是768x1024,它们被“堆叠”在页面上(即页面大小为768x3072 [1024 * 3 = 3072]),当你点击链接时,我使用scrollTo jquery插件滚动到下一个“幻灯片”,并且聚焦于一个输入元素。.focus(),请问有谁知道如何做到这一点?

请考虑我的解决方案。它应该是解决这个问题的最佳方法,只需挂钩“focusin”。 - Paul Lan
2023解决方案在这里:https://dev59.com/5XA85IYBdhLWcg3wEPVL#76731361 - Raine Revere
12个回答

14

我发现在UIWebView中,document.body有时也会被移动。所以我使用:

    input.onfocus = function () {
        window.scrollTo(0, 0);
        document.body.scrollTop = 0;
    }

61
不能停止滚动,但会滚动到0,0位置。这可能不是想要的结果。 - Petr Peller
不是一个好的解决方案,如果iframe包含多个输入框,我们不希望用户为每个聚焦的元素向上滚动。 - Enmanuel Duran
你会在 focus() 后面添加这个吗?还是在前面? - AnaCS

11

糟糕,建议使用的window.scrollTo效果不佳,导致结果不可预测。

尝试这个更好的解决方案:

jQuery('body').bind('focusin focus', function(e){
  e.preventDefault();
})

或者,只需连接您的输入:

jQuery('input.your-input-class').bind('focusin focus', function(e){
  e.preventDefault();
})

为什么?浏览器可能会默认在“focusin”事件触发时将焦点表单元素滚动到可见区域(Firefox有一个bug,因此应该使用focus事件)。因此,只需明确告诉它们不要这样做即可。

顺便说一下,如果您的代码中使用element.focus()触发focus事件,则即使采用上述解决方案也无法解决问题。

因此,解决方法是将focus触发器替换为select,即:

element.select()

除了 element.focus() 之外,如果您不喜欢 element.select() 方法,因为它会选中输入元素中的文本,则可以尝试创建一个输入元素文本的 Range 对象 并将其折叠,如果愿意的话,很抱歉暂时没有时间尝试。


很高兴听到有更好的解决方案。我同意window.scrollTo有时会表现不良。 - Paul Greyson
这对我不起作用;iOS9 iPhone 6+在键盘已经打开并且页面已经滚动后才触发事件。 - RebelFist
2
是的。在iOS 9中,确认不起作用。尝试使用focus、focusin和select。 - Will Lanni
在我的情况下,我需要滚动仍然可以工作,但是当我通过js进行聚焦时不会触发。我添加了我的解决方案,以防其他人需要。对我来说,在iOS9和iOS10上也有效。 - Dominik
无法阻止焦点。 - aboutqx

6
为了防止浏览器滚动到您将焦点移动到的元素,我使用jQuery的one事件监听器。在我将焦点移动到元素之前,我们将侦听器添加到scroll事件并计数滚动。然后,jQuery会删除事件监听器。
var oldScroll = $(window).scrollTop();

$( window ).one('scroll', function() {
    $(window).scrollTop( oldScroll ); //disable scroll just once
});

$('.js-your-element').focus();

这种方法对我来说似乎很简单、有效,并且在我所做的所有测试中都表现出色。希望能对某些人有所帮助。

在iOS 16.5.1中,保持滚动位置,但屏幕跳动会分散注意力。 - Raine Revere

3
如果您不希望输入内容可编辑,那么kpozin的答案就足够了。但是一旦您删除readonly属性后,onfocusonclick会使输入框再次滚动到焦点位置。
真正有用并且不影响焦点或文本输入能力的方法是在输入元素中添加onFocus="window.scrollTo(0, 0);"
当然,您必须确保相关输入不被屏幕键盘覆盖!
另请参阅此帖子:Preventing an <input> element from scrolling the screen on iPhone?

2

更新 - 我已经在几个不同的地方看到了window.scroll(0,0)这个解决方案,但似乎只会使情况变得更糟。我在页面上有多个内联文本输入框,所以当在它们之间移动焦点时,在Safari中自动上下滚动几乎让页面无法使用,特别是在横向方向。

在与iOS 8进行了一周的斗争后,我发现这可以停止滚动。当从一个元素切换到另一个元素时,需要将onblur事件附加到某些东西:

var moveFocus = function (blurId, focusId) {
    var blurInput = document.getElementById(blurId);
    var focusInput = document.getElementById(focusId);
    if (blurInput && focusInput) {
        blurInput.onblur = function () {
            if (focusInput.setSelectionRange && focusInput.setSelectionRange()) {
                var len = focusInput.value.length;
                focusInput.setSelectionRange(len, len);
            }
            focusInput.focus();
        };
        focusInput.focus();
    };
};

1
无论何种原因,似乎您可以通过对自动聚焦的输入容器应用关键帧动画来减轻这种情况。
function App() {
  const [isSearching, setIsSearching] = useState(false);

  return (
    <FixedContainer>
      {isSearching && (
        <Box>
          <Input autoFocus type="text" placeholder="click me" onBlur={() => setIsSearching(false)} />
        </Box>
      )}
    </FixedContainer>
  )
}

const fadeInKeyframes = keyframes`
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
`;

const Box = styled.div`
  animation-name: ${fadeInKeyframes};
  animation-duration: 0.1s;
  animation-timing-function: ease;
  animation-delay: 0s;
  animation-iteration-count: 1;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-play-state: running;
`;

https://stackblitz.com/edit/react-ios-input-scroll

示例代码:https://react-ios-input-scroll.stackblitz.io


当我程序更改浏览器选择时,这对我有用,但是当用户点击输入时却不起作用(在我的情况下好像也没关系)。更简单的CSS:.preventAutoscroll { animation: 0.01s 1 fadeInKeyframes; } - Raine Revere

0
如果您正在使用Cordova开发移动Web应用程序,那么有一个插件可以解决这个问题:
对我有用的插件是Telerik Keyboard Plugin。它使用基本的UIWebView。安装该插件。
cordova plugin add ionic-plugin-keyboard

在您的应用程序加载后调用此命令:

cordova.plugins.Keyboard.disableScroll(true);

如果您正在使用WKWebView,您可以使用此插件


0
这对我有用(使用jQuery)。它允许滚动,当您离开输入时,会将您返回到正确的位置。
    var saveScrollLeft;
    $("input, textarea")
        .focus(function () {
            clearTimeout(blurTimeoutId);
            saveScrollLeft = $("body").scrollLeft();
            })
        .blur(function () {
            // The user might be moving from one input to another, so we don't want to quickly scroll on blur.  Wait a second and see if they are off all inputs.
            blurTimeoutId = setTimeout(function () {
                $(window).scrollLeft(saveScrollLeft);
                }, 1000);
        });

0
尝试使用BLSully的此答案。最初为所有输入元素添加readonly="readonly"属性,这将防止Mobile Safari滚动到它。对于每个元素,在焦点上删除属性,在模糊时再次添加属性。

2
在iOS8中,只读输入框无法获得焦点,因此这是行不通的。 - Ben Hull
2
此外,这对于可访问性来说也不是好的选择,因为它会让人们/阅读软件认为那些字段实际上是不可编辑的。 - Jérôme Beau
如果我在touchstart事件中将readOnly设置为true,并在touchend事件中将readOnly设置为false并使用target.focus({preventScroll: true}),那么它对我起作用。 链接 - Slavik Salamandyk

0

提供的解决方案都对我没用。

由于抓取焦点的表单(并将页面初始显示滚动到该表单下面)在屏幕外,所以我只需向表单添加一个淡入效果即可。

因此,我添加了一个名为fade-in的类名,相应的CSS为display:none

使用jQuery,我只需要在文档准备好后执行jQuery(".fade-in").fadeIn();,问题就解决了。

这显然不仅限于使用jQuery。可以使用Vanilla js进行淡入效果。


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