繁体   English   中英

如何在移动 Safari 中打开虚拟键盘时将视口固定到位?

[英]How to fix viewport in place when virtual keyboard opens in mobile Safari?

目标

在移动版 Safari 上,当虚拟键盘打开时,屏幕应呈现如下图像: 在此处输入图片说明

在哪里:

  • 导航栏和输入固定到位
  • 短信列表可滚动

问题

在移动版 Safari 上,当软键盘打开时,在输入或导航栏上拖动可以上下移动整个视口。

我有一个屏幕截图视频演示了这个问题: https : //youtu.be/GStBjRVpoGU

我已经在这个问题上花了几个月的时间,包括在 Stack Overflow 上浏览了许多类似的问题,但我一直无法找到一个有效的解决方案(或者,至少,一个我能够解决的问题)。

背景

此应用程序是一个混合移动应用程序:使用 React.js 构建为 Web 应用程序,但使用 WebView 组件封装在 React Native 应用程序中。 然而,即使在普通的移动 Safari 窗口中打开 Web 应用程序,也存在同样的问题。

Mobile Safari 有一个相关问题,软键盘在打开时会将整个视口向上推,从而使视口的上半部分向上推离屏幕。 这个优秀的博客提供了该问题的描述和解决方案。 我实施了该解决方案。 它在软键盘打开时阻止了视口向上移动,但在软键盘打开后视口仍然可以滑动。

另一个问题是移动版 Safari 在打开/关闭软键盘时不会更新window.innerHeight 为了解决这个问题,我在 React Native 应用程序中使用了react-native-keyboard-spacer ,有点像这样:

render() {
    return (
      <React.Fragment>
        <SafeAreaView >
          <WebView/>
        </SafeAreaView>
        <KeyboardSpacer />
      </React.Fragment>
    );
  }

这会在软键盘打开/关闭时更改 Webview 的高度,因此window.innerHeight等也会更改。

position: fixed; 当软键盘打开时,移动版 Safari 效果不佳,所以我使用了position: absolute; 相反,感谢另一个非常有用的博客中的建议。

我创建了一个代码沙箱来演示这个问题。 在移动版Safari中打开,可以看到虚拟键盘打开后的屏幕滑动。 你也可以在这里查看实际的代码沙箱代码,它代表了我最接近解决这个问题的方法。

不过,关于代码沙箱需要注意的一件事。 没有 WebView 或 KeyboardSpacer:它只是一个网页。 因此,我不得不硬编码一些高度。但是如果你在移动版 Safari 中打开它,你会看到一旦软键盘打开,视口就会在整个地方滑动。

有没有人见过这个特定的问题? 你怎么修好它的? 提前谢谢了。

JMathew的帮助下,我找到了解决此问题的方法。

请参阅此处的有效代码和框示例。

  1. 将您的导航栏、消息列表和输入放入容器 div。
  2. 将引用添加到这些容器 div。 例如:
  const messageListContainerRef = useRef<HTMLDivElement>(null);

  //...

  return (
    //...
    <div ref={messageListContainerRef}>
      <MessageList/>
    </div>
    //...
  )
  1. 当虚拟键盘打开时(当虚拟输入被聚焦时),将 touchmove 事件的事件侦听器添加到inputContainerRefnavbarContainerRef 使用它来防止触摸移动事件上的preventDefault() ,这将阻止用户能够上下滑动输入和导航栏。 例如:
if (inputContainerRef.current) {
  inputContainerRef.current.addEventListener('touchmove', (e) => {
    e.preventDefault();
  });
}
  1. 您仍然希望能够滚动浏览消息列表,因此您不能只对它使用preventDefault() 相反,使用此解决方案通过设置scrollTop值来防止用户滚动页面的底部(和顶部):
if (messageListContainerRef.current) {
  messageListContainerRef.current.addEventListener('touchmove', (e: any) => {
    if (!e.currentTarget) {
      return;
    }
    if (e.currentTarget.scrollTop === 0) {
      e.currentTarget.scrollTop = 1;
    } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop +
                                                e.currentTarget.offsetHeight) {
      e.currentTarget.scrollTop -= 1;
    }
  });
}

根据您的需要/需要,您可以在组件安装上设置这些touchmove事件侦听器,而不是在输入焦点上。 如果这对您有用,您甚至可以为整个 document.body 设置它们。

Javascript 解决方案,最后,我们得到了完美的解决方案。

window.scrollBy(0, 100); // Scroll 100px downwards 
window.scrollBy(100, 0); // Scroll 100px to the right

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM