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

问题描述 投票:3回答:1

目标

在移动Safari上,打开虚拟键盘后,屏幕应呈现如下图所示:enter image description here

其中:

  • 导航栏和输入固定在适当位置
  • 短信列表是可滚动的

问题

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

我有一个演示问题的屏幕录像:https://youtu.be/GStBjRVpoGU

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

背景

[此应用程序是一个混合移动应用程序:使用React.js作为Web应用程序构建,但使用WebView组件包装在React Native应用程序中。但是,即使在常规的移动Safari窗口中打开了Web应用程序,也存在相同的问题。

Mobile Safari存在一个相关问题,即软键盘在打开时会将整个视口向上推,从而将视口的上半部分向上推并移出屏幕。 This excellent blog同时提供了该问题的说明和解决方案。我实现了该解决方案。当软键盘打开时,它阻止了视口向上移动,但是在软键盘打开后,视口仍然可以在周围滑动。

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

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

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

[也众所周知,当打开软键盘时,移动Safari上的position: fixed;不能很好地工作,因此,由于其他position: absolute;的建议,我改用了very useful blog

我创建了一个code sandbox来演示该问题。在打开虚拟键盘后,在移动Safari中将其打开以查看屏幕幻灯片。您也可以使用实际的代码沙箱代码here,它代表我最近解决此问题的方式。

不过,关于代码沙箱需要注意的一件事。没有WebView或KeyboardSpacer:它只是一个网页。因此,我必须对一些高度进行硬编码。但是,如果您在移动Safari中打开它,则一旦打开软键盘,视口就会在整个位置滑动。

以前有人见过这个特殊问题吗?你怎么修好它的?提前非常感谢。

javascript css reactjs mobile-safari hybrid-mobile-app
1个回答
0
投票
借助于JMathew,我找到了解决此问题的方法。

请参见工作代码和框示例here

    将您的导航栏,消息列表,并输入到容器div中。
  1. 向这些容器div添加引用。例如:
  • const messageListContainerRef = useRef<HTMLDivElement>(null); //... return ( //... <div ref={messageListContainerRef}> <MessageList/> </div> //... )
      [打开虚拟键盘时(当虚拟输入被聚焦时),将用于touchmove事件的事件监听器添加到inputContainerRefnavbarContainerRef。将其用于触摸移动事件上的preventDefault(),这将防止用户能够上下滑动输入和导航栏。例如:
  • if (inputContainerRef.current) { inputContainerRef.current.addEventListener('touchmove', (e) => { e.preventDefault(); }); }
      您仍然希望能够滚动查看消息列表,因此不能仅在其上单击preventDefault()。而是使用this solution通过设置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设置它们,如果那对您有用。
  • 最新问题
    © www.soinside.com 2019 - 2024. All rights reserved.