如何使移动键盘外观与 div 发生碰撞而不是绝对将其自身定位在其上方?

2023-12-02

我正在开发一个简单的聊天组件,但遇到一个问题,在移动设备上,如果我单击文本框发送消息,而不是弹出其上方的消息列表,虚拟键盘会将自己绝对定位在它。

这是不可取的,因为我希望用户在键入消息时能够看到最新消息。但是,我不知道如何纠正这种行为。 (而且我不能将文本框放在messagesdiv 因为它应该始终位于底部)

我创建了一个示例片段来演示问题在这里(添加底部边距演示的问题与单击文本框并弹出移动键盘相同)

基本上,如果您滚动到底部并单击“添加边距”按钮,您会看到它不是将内容推到其上方(这样您仍然可以看到最新消息),而是向上滚动。有什么办法可以避免这种情况吗?

这是代码的副本,以防小提琴出现故障:

<div class="container">
  <div class="messages">
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
    <div class="message">hello</div>
  </div>
  <div class="send-message">
    <input />
  </div>
</div>

<button onclick="test()">add margin</button>

.container {
  width: 400px;
  height: 300px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  overflow-y: auto;
  height: 100%;
}

.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}

function test() {
  document.querySelector(".send-message").classList.toggle("some-margin")
}

幸运的是,有。这里的问题是你没有处理滚动位置.messages当。。。的时候.send-messagediv 扩展(即获得更多边距)。我想你想调整它以便滚动位置最后visible消息作为其枢轴(即 div 展开之前的最后一条可见消息必须在 div 展开之后出现,反之亦然)。要调整所述滚动位置,这里有一个最小的工作示例(我稍微更改了您的 HTML 内容,以便您可以指示最后一条消息是什么,并且我调整了您的 JS 代码):

function test() {
  let messageBox = document.querySelector('.messages')
  let beforeMessageBoxHeight = messageBox.clientHeight
  let afterMessageBoxHeight
  let messageBoxHeightDifference
  let beforeScrollTop = messageBox.scrollTop
  let afterScrollTop
  document.querySelector(".send-message").classList.toggle("some-margin")
  afterMessageBoxHeight = messageBox.clientHeight
  messageBoxHeightDifference = beforeMessageBoxHeight - afterMessageBoxHeight
  afterScrollTop = beforeScrollTop + messageBoxHeightDifference
  messageBox.scrollTop = afterScrollTop
}
.container {
  width: 400px;
  height: 300px;
  border: 1px solid #333;
  display: flex;
  flex-direction: column;
}

.messages {
  overflow-y: auto;
  height: 100%;
}

.send-message {
  width: 100%;
  display: flex;
  flex-direction: column;
}

.some-margin {
  margin-bottom: 100px;
}
<div class="container">
  <div class="messages">
    <div class="message">hello1</div>
    <div class="message">hello2</div>
    <div class="message">hello3</div>
    <div class="message">hello4</div>
    <div class="message">hello5</div>
    <div class="message">hello6</div>
    <div class="message">hello7</div>
    <div class="message">hello8</div>
    <div class="message">hello9</div>
    <div class="message">hello1</div>
    <div class="message">hello2</div>
    <div class="message">hello3</div>
    <div class="message">hello4</div>
    <div class="message">hello5</div>
    <div class="message">hello6</div>
    <div class="message">hello7</div>
    <div class="message">hello8</div>
    <div class="message">hello9</div>
    <div class="message">hello1</div>
    <div class="message">hello2</div>
  </div>
  <div class="send-message">
    <input />
  </div>
</div>

<button onclick="test()">add margin</button>

这个想法是:

  • Get the clientHeight(可见高度,请阅读 MDN 文档以获取更多详细信息)在 div 展开之前
  • Get the scrollTop值(从最上面的可见/不可见元素到最上面的可见元素测量的像素数)
  • 当 div (.send-message) 展开,可见高度 (clientHeight)自动缩小尺寸。这scrollTop值仍然相同,这意味着最上面的可见元素beforediv 展开后仍然可见。然而,这不是我们想要的:我们希望在 div 展开之前最底部的可见元素保持可见
  • 我们测量div展开后和div展开前的高度差。从逻辑上讲,高度差导致可见消息的底部部分(在 div 展开之前)显得不可见(由于溢出)。
  • 要解决这个问题,请将高度差添加到之前的高度差中scrollTop值,以便在 div 展开之前很好地滚动到最底部的可见消息。
  • 瞧,它有效。当 div 缩回时,您可以应用相同的逻辑。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使移动键盘外观与 div 发生碰撞而不是绝对将其自身定位在其上方? 的相关文章