【问题标题】:How to make the mobile keyboard appearance bump the div rather than absolutely position itself over it?如何让移动键盘外观撞到 div 而不是绝对定位在它上面?
【发布时间】:2020-01-04 02:49:00
【问题描述】:

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

这是不可取的,因为我希望用户在输入消息时能够看到最新消息。但是,我无法弄清楚如何纠正这种行为。 (我不能将文本框放在 messages div 中,因为它应该始终位于底部)

我创建了一个演示 the problem here 的示例 sn-p(添加底部边距与单击文本框并弹出移动键盘相同的问题)

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

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

<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")
}

【问题讨论】:

    标签: javascript android html css


    【解决方案1】:

    幸运的是,有。这里的问题是当.send-message div 扩展(即获得更多边距)时,您没有处理.messages 的滚动位置。我假设您想调整它,以便滚动位置将最后一个 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>

    这个想法是:

    • 在 div 展开之前获取 clientHeight(可见高度,请阅读 MDN 文档了解更多详细信息)
    • 获取scrollTop 值(从最顶部可见/不可见元素到最顶部可见元素测量的像素数)
    • 当 div (.send-message) 展开时,可见高度 (clientHeight) 会自动缩小。 scrollTop 值仍然相同,这意味着 div 展开 before 的最顶部可见元素仍然可见。然而,这不是我们想要的:我们希望在 div 展开之前最底部的可见元素保持可见
    • 我们在 div 展开之后和 div 展开之前测量高度差。从逻辑上讲,高度差使可见消息的底部(在 div 展开之前)看起来不可见(由于溢出)。
    • 要解决该问题,请将高度差添加到先前的scrollTop 值,以便在 div 展开之前它可以很好地滚动到最底部的可见消息。
    • 瞧,它起作用了。当 div 收回时,您可以应用相同的逻辑。

    【讨论】:

    • 我希望有一个纯 CSS 解决方案,但如果这是最好的解决方案,那么我会接受它。
    • @RyanPeschel 哦,您应该提到,在您目前的原始问题中,您暗示在您的问题中任何解决方案都可以有没有办法避免这种情况?跨度>
    • 是的,对不起,我应该更清楚。无论如何,如果没有 CSS 解决方案,那么我一定会使用它。但一般来说,如果存在 JS 解决方案,那么纯 CSS 解决方案通常更受欢迎,IIRC。
    猜你喜欢
    • 2016-01-08
    • 2011-02-21
    • 2018-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多