javascript - 仅当不在消息 div 的底部附近时,保持滚动位置才有效
问题描述
我正在尝试模仿其他移动聊天应用程序,当您选择send-message
文本框并打开虚拟键盘时,最底部的消息仍在视图中。似乎没有办法用 CSS 惊人地做到这一点,所以 JavaScript resize
(显然是找出键盘何时打开和关闭的唯一方法)事件和手动滚动来救援。
有人提供了这个解决方案,我发现了这个解决方案,这两个似乎都有效。
除了一种情况。出于某种原因,如果您在MOBILE_KEYBOARD_HEIGHT
消息 div 底部的(在我的情况下为 250 像素)像素内,当您关闭移动键盘时,会发生一些奇怪的事情。使用前一种解决方案,它会滚动到底部。而对于后一种解决方案,它会MOBILE_KEYBOARD_HEIGHT
从底部向上滚动像素。
如果您滚动到此高度以上,则上面提供的两种解决方案都可以完美运行。只有当您接近底部时,他们才会遇到这个小问题。
我想也许这只是我的程序用一些奇怪的杂散代码造成的,但不,我什至复制了一个小提琴,它有这个确切的问题。很抱歉让调试变得如此困难,但如果你在手机上访问https://jsfiddle.net/t596hy8d/6/show(显示后缀提供全屏模式),你应该能够看到相同的行为。
这种行为是,如果您向上滚动足够多,打开和关闭键盘会保持该位置。但是,如果您在底部像素内关闭键盘MOBILE_KEYBOARD_HEIGHT
,您会发现它会滚动到底部。
这是什么原因造成的?
代码复制在这里:
window.onload = function(e){
document.querySelector(".messages").scrollTop = 10000;
bottomScroller(document.querySelector(".messages"));
}
function bottomScroller(scroller) {
let scrollBottom = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight;
scroller.addEventListener('scroll', () => {
scrollBottom = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight;
});
window.addEventListener('resize', () => {
scroller.scrollTop = scroller.scrollHeight - scrollBottom - scroller.clientHeight;
scrollBottom = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight;
});
}
.container {
width: 400px;
height: 87vh;
border: 1px solid #333;
display: flex;
flex-direction: column;
}
.messages {
overflow-y: auto;
height: 100%;
}
.send-message {
width: 100%;
display: flex;
flex-direction: column;
}
<div class="container">
<div class="messages">
<div class="message">hello 1</div>
<div class="message">hello 2</div>
<div class="message">hello 3</div>
<div class="message">hello 4</div>
<div class="message">hello 5</div>
<div class="message">hello 6 </div>
<div class="message">hello 7</div>
<div class="message">hello 8</div>
<div class="message">hello 9</div>
<div class="message">hello 10</div>
<div class="message">hello 11</div>
<div class="message">hello 12</div>
<div class="message">hello 13</div>
<div class="message">hello 14</div>
<div class="message">hello 15</div>
<div class="message">hello 16</div>
<div class="message">hello 17</div>
<div class="message">hello 18</div>
<div class="message">hello 19</div>
<div class="message">hello 20</div>
<div class="message">hello 21</div>
<div class="message">hello 22</div>
<div class="message">hello 23</div>
<div class="message">hello 24</div>
<div class="message">hello 25</div>
<div class="message">hello 26</div>
<div class="message">hello 27</div>
<div class="message">hello 28</div>
<div class="message">hello 29</div>
<div class="message">hello 30</div>
<div class="message">hello 31</div>
<div class="message">hello 32</div>
<div class="message">hello 33</div>
<div class="message">hello 34</div>
<div class="message">hello 35</div>
<div class="message">hello 36</div>
<div class="message">hello 37</div>
<div class="message">hello 38</div>
<div class="message">hello 39</div>
</div>
<div class="send-message">
<input />
</div>
</div>
解决方案
我终于找到了一个真正有效的解决方案。尽管它可能并不理想,但它实际上适用于所有情况。这是代码:
bottomScroller(document.querySelector(".messages"));
bottomScroller = scroller => {
let pxFromBottom = 0;
let calcPxFromBottom = () => pxFromBottom = scroller.scrollHeight - (scroller.scrollTop + scroller.clientHeight);
setInterval(calcPxFromBottom, 500);
window.addEventListener('resize', () => {
scroller.scrollTop = scroller.scrollHeight - pxFromBottom - scroller.clientHeight;
});
}
我一路上的一些顿悟:
关闭虚拟键盘时,会在事件
scroll
之前立即发生resize
事件。这似乎只在关闭键盘时发生,而不是打开它。这就是你不能使用scroll
事件来设置的原因pxFromBottom
,因为如果你接近底部,它会在scroll
事件之前的resize
事件中将自己设置为 0,从而打乱计算。所有解决方案在消息 div 底部附近都有困难的另一个原因是有点难以理解。例如,在我的调整大小解决方案中
scrollTop
,我只是在打开或关闭虚拟键盘时添加或减去 250(移动键盘高度) 。除了靠近底部外,这非常有效。为什么?因为假设您距离底部 50 像素并关闭键盘。它将从scrollTop
(键盘高度)中减去 250,但它应该只减去 50!所以在靠近底部关闭键盘时它总是会重置到错误的固定位置。我也相信您不能在此解决方案中使用
onFocus
和onBlur
事件,因为这些仅在最初选择文本框以打开键盘时才会发生。您完全可以在不激活这些事件的情况下打开和关闭移动键盘,因此它们无法在此处使用。
我相信以上几点对于开发解决方案很重要,因为它们起初并不明显,但会阻止开发强大的解决方案。
我不喜欢这个解决方案(间隔有点低效并且容易出现竞争条件),但我找不到更好的总是有效的方法。
推荐阅读
- webpack - 使用 webpack 从静态文件夹目录导入图片名称
- mysql - 错误 DbVisualizer 创建触发器
- mysql - SQL 游标确定中值
- scheme - 将已知参数传递给 Scheme 函数
- java - 使用单个可运行的 3 个线程连续打印 1 、 2 、 3 不起作用
- mysql - mysql“等待表元数据锁定”上的单个连接到 DROP INDEX
- html - 如何使用 Nokogiri 在 span 标签之间打印文本?
- ios - datePicker 未显示在所需位置
- webstorm - 使用 Flow 作为 JavaScript 语言时参考的 WebStorm 慢速导航
- python - Pandas:按列条件拆分