如何使移动键盘外观与div碰撞,而不是将其自身绝对定位在div上? [英] How to make the mobile keyboard appearance bump the div rather than absolutely position itself over it?

查看:65
本文介绍了如何使移动键盘外观与div碰撞,而不是将其自身绝对定位在div上?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm developing a simple chat component and I'm having an issue where, on mobile, if I click the textbox to send a message, rather than bumping up the messages list above it, the virtual keyboard instead absolutely positions itself on top of it.

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

This is undesirable because I want the user to be able to see the latest message while typing a message. However, I cannot figure out how to rectify this behavior. (and I cannot put the textbox inside the messages div because it should always be at the bottom)

我创建了一个示例代码段,演示了此处的问题(添加底部边距演示了问题等同于单击文本框并弹出移动键盘)

I've created an example snippet that demonstrates the problem here (adding bottom margin demonstrates the problem identically to clicking the textbox and having the mobile keyboard pop up)

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

Basically, if you scroll to the bottom and click the "add margin" button, you'll see that rather than push the contents above it, such that you can still see the latest message, it instead scrolls up. Is there any way to avoid this?

这是小提琴掉下来的情况下的代码副本:

Here is a copy of the code in case the fiddle goes down:

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

推荐答案

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

Fortunately, there is. The problem here is you are not handling the scroll position of the .messages when the .send-message div expands (i.e. gets more margin). I presume you want to adjust it so that the scroll position takes the last visible message as its pivot (i.e. the last visible message before the div expands has to appear after the div expands, and vice-versa). To adjust said scroll position, here's a minimal working example (I changed your HTML content a little so that you can indicate what the last message is and I adjusted your JS code):

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扩展之前的最强可见元素 仍然可见.但是,这并不是我们想要的:我们希望在div扩展之前保持最底端的可见元素
  • 我们在div扩展之后和div扩展之前测量高度差.从逻辑上讲,高度差是导致可见消息的底部(在div扩展之前)变得不可见(由于溢出)的原因.
  • 要解决该问题,请将高度差添加到先前的scrollTop值,以便在div扩展之前将其很好地滚动到最底部的可见消息.
  • Voila,它有效.当div撤消时,您可以应用相同的逻辑.
  • Get the clientHeight (visible height, read MDN Docs for more details) before the div expands
  • Get the scrollTop value (how many pixels measured from the topmost visible/invisible element to the topmost visible element)
  • When the div (.send-message) expands, the visible height (clientHeight) automatically reduces in size. The scrollTop value is still the same, which means that the topmost visible element before the div expands will still be visible. However, that is not what we want: we want the bottommost visible element before the div expands to remain visible
  • We measure the height difference after the div expands and before the div expands. Logically, the height difference is what is making the bottom parts of the visible messages (before the div expands) to appear invisible (due to overflow).
  • To address that issue, add the height difference to the previous scrollTop value so that it scrolls nicely to the bottommost visible message before the div expands.
  • Voila, it works. You can apply the same logic when the div retracts.

这篇关于如何使移动键盘外观与div碰撞,而不是将其自身绝对定位在div上?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆