javascript - 如何使移动键盘外观撞到 div 而不是绝对定位在它上面?
问题描述
我正在开发一个简单的聊天组件,我遇到了一个问题,在移动设备上,如果我单击文本框发送消息,而不是在其上方弹出消息列表,虚拟键盘反而绝对将自己定位在它。
这是不可取的,因为我希望用户在输入消息时能够看到最新消息。但是,我无法弄清楚如何纠正这种行为。(而且我不能将文本框放在messages
div 中,因为它应该始终位于底部)
我创建了一个示例片段来演示此处的问题(添加底部边距演示的问题与单击文本框并弹出移动键盘相同)
基本上,如果您滚动到底部并单击“添加边距”按钮,您会看到不是将内容推到它上面,这样您仍然可以看到最新消息,而是向上滚动。有没有办法避免这种情况?
这是代码的副本,以防小提琴出现故障:
<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")
}
解决方案
幸运的是,有。这里的问题是您没有处理div 扩展.messages
时的滚动位置(即获得更多边距)。.send-message
我假设您想要调整它,以便滚动位置将最后一个可见消息作为其枢轴(即 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 展开之前最顶部的可见元素仍然可见。然而,这不是我们想要的:我们希望在 div 展开之前最底部的可见元素保持可见 - 我们测量 div 展开后和 div 展开前的高度差。从逻辑上讲,高度差是使可见消息的底部(在 div 展开之前)看起来不可见(由于溢出)的原因。
- 要解决该问题,请将高度差添加到先前的
scrollTop
值,以便它在 div 展开之前很好地滚动到最底部的可见消息。 - 瞧,它有效。当 div 缩回时,您可以应用相同的逻辑。
推荐阅读
- python - 在 ubuntu 18.04 上安装/导入 pyqt5 有困难
- php - Laravel - firstOrCreate() 将参数 1 检测为非数组,但它是
- r - ggplot的多次使用
- android - Xamarin.Forms.Droid 资源,不明确的术语/构建操作的随机变化的缺失资源
- opencv - Yocto构建中opencv中的Gsteamer冲突声明
- c# - 指定 Nuget 包平台目标
- kubernetes - Kubernetes 中的 Flink 会话集群和作业提交
- reactjs - 错误格式的钩子获取错误“效果函数不得返回除函数之外的任何内容......”
- javascript - 使用 Angular 7 同步水平滚动
- java - 表单中的 ModelAttribute 无法与对象绑定(Spring MVC)