繁体   English   中英

Mobile safari - 在屏幕键盘上隐藏一些元素

[英]Mobile safari - on screen keyboard hiding some elements

我正在使用 flexbox 为 HTML 聊天应用程序构建一个非常简单的 POC。 这个想法是让聊天消息从消息窗口的底部开始。 典型的东西。

我通过使用一个嵌套的 flexbox 来做到这一点,其中一个内部 div 设置为 flex-direction: column 和一个外部 div 设置为 flex-direction: column-reverse 和 overflow-y: auto:

<div class="outer">
    <div id="messages" class="inner">
        <div class="message">hello</div>
    </div>
</div>
.outer {
    flex-grow: 1;
    display: flex;
    flex-direction: column-reverse;
    overflow-y: auto;
}

.inner {
    display: flex;
    flex-direction: column;
}

它适用于桌面浏览器:

桌面

它在 iOS Safari 上也可以正常工作,最多可以收到一定数量的消息。 但是在某些时候,新消息会隐藏在屏幕键盘后面,查看它们的唯一方法是手动向下滚动或关闭屏幕键盘。 注意:再次打开键盘将不再隐藏消息,关闭键盘似乎重置滚动。

打开 Safari 开发工具会发现一些有趣的东西。 When selecting an html element Safari thinks it is where it should be, in fact the preceding element is shown:

移动的

请注意我如何选择最后一个元素“二”,但开发工具突出显示消息“一”

我注意到了别的东西。 将外部 div 的溢出-y 更改为隐藏可以解决问题,但显然我不能再滚动浏览消息。

我猜这个问题与有两组滚动条有关,一组用于 div,另一组用于由键盘移动的页面本身。

有谁知道为什么会发生这种情况以及如何防止它?

我创建了一个小提琴并在S3上托管了页面

在我的手机上,添加大约 12/13 条消息足以让他们开始“隐藏”在键盘后面。

可能需要这种 iOS 行为,因为它可以防止打开键盘时突然跳转,但如果您想覆盖它,请尝试添加到您的代码中:

const outer = document.querySelector(".outer")

const scrollToBottom = () => {
  outer.scrollTop = 0
}

input.addEventListener("focus", scrollToBottom)

 const messages = document.getElementById("messages"); const input = document.getElementById("messageInput"); const target = document.getElementById("send"); const template = document.getElementById("messageTemplate"); const pushMessage = () => { const clone = template.content.cloneNode(true); clone.querySelector("div.message").innerText = input.value; messages.appendChild(clone); } const keyUpHandler = (e) => { if (e.key === 'Enter') pushMessage() } target.addEventListener("click", pushMessage) input.addEventListener("keyup", keyUpHandler) const outer = document.querySelector('.outer'); const scrollToBottom = () => { outer.scrollTop = 0; } input.addEventListener("focus", scrollToBottom)
 .page { position: fixed; top: 0; left: 0; width: 100%; display: flex; flex-direction: column; height: 100%; } .header, .footer { padding: 1rem; background-color: lightgrey; display: flex; flex-direction: row; } .outer { flex-grow: 1; display: flex; flex-direction: column-reverse; overflow-y: auto; /*overflow-y: hidden;*/ } .inner { display: flex; flex-direction: column; } .message { padding: 1rem; }
 <div class="page"> <div class="header"> header </div> <div class="outer"> <div id="messages" class="inner"> <div class="message">hello</div> </div> </div> <div class="footer"> <input id="messageInput" type="text" placeholder="Enter your message" /> <button id="send">send</button> </div> </div> <template id="messageTemplate"> <div class="message"></div> </template>

我通常做的是围绕整个页面创建一个 div。 这个元素的高度为 100vh,宽度为 100vw 以及相对位置。

这样你就有了一个可滚动的元素,你可以在焦点上滚动到底部。

此外,例如,如果您尝试将某些东西粘贴(绝对定位)到页面底部,它实际上将位于键盘上方。

我遇到了这个确切的问题(也构建了聊天 UI)并设法最终找到了解决方案

在 Safari 控制台中玩耍后,我意识到如果我将scrollTop设置为0 ,它会正确地将我跳到线程的底部,但是如果我随后发送另一条消息,则消息将隐藏在输入后面。

不过有趣的是,如果我将它设置为类似的值(如-1 ),它会再次将我跳到底部。

有了这种见解,我尝试将其结合起来,并找到了一个可行的解决方案!

这就是我最终的结果:

 scrollNewMessage() {
  const scrollTop = this.$refs["message-thread-wrapper"].scrollTop

  // iOS Safari refuses to update scrollTop if the given value is the same as its
  // current value. That would be fine, except that the current value is _incorrect_
  // when the keyboard is open
  // This was resulting in messages hiding behind the message compose box
  // Ensuring the value is always different fixes it
  this.$refs["message-thread-wrapper"].scrollTop = scrollTop === 0 ? -1 : 0
},

暂无
暂无

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

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