javascript - 仅当不靠近 messages div 的底部时,保持滚动位置才有效

标签 javascript android html css reactjs

我正在尝试模仿其他移动聊天应用程序,当您选择send-message文本框并打开虚拟键盘时,最底部的消息仍然可见。似乎没有办法用 CSS 来惊人地做到这一点,所以 JavaScript resize (唯一找出键盘何时打开和关闭的方法)事件和手动滚动来救援。

有人提供this solution我发现this solution ,这两者似乎都有效。

除了一种情况。由于某种原因,如果您位于消息 div 底部的 MOBILE_KEYBOARD_HEIGHT(在我的情况下为 250 像素)像素内,则当您关闭移动键盘时,会发生一些奇怪的情况。对于前一种解决方案,它滚动到底部。对于后一种解决方案,它会从底部向上滚动 MOBILE_KEYBOARD_HEIGHT 像素。

如果您滚动到这个高度以上,上面提供的两种解决方案都可以完美地工作。只有当你接近底部时,他们才会遇到这个小问题。

我想也许这只是我的程序导致了一些奇怪的杂散代码,但不,我什至重现了一个 fiddle ,它有这个确切的问题。我很抱歉让调试变得如此困难,但是如果您转到 https://jsfiddle.net/t596hy8d/6/show (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;
  });
}

我一路走来的一些顿悟:

  1. 关闭虚拟键盘时,scroll 事件会在 resize 事件之前立即发生。这似乎只发生在关闭键盘时,而不是打开键盘时。 就是你不能使用 scroll 事件设置 pxFromBottom 的原因,因为如果你接近底部,它会在scroll 事件就在 resize 事件之前,搞乱了计算。

  2. 所有解决方案在消息 div 底部附近遇到困难的另一个原因有点难以理解。例如,在my resize solution中我只是在打开或关闭虚拟键盘时为 scrollTop 添加或减去 250(移动键盘高度)。除了靠近底部之外,这一切都完美。为什么?因为假设您距底部 50 像素并关闭键盘。它会从 scrollTop(键盘高度)中减去 250,但它应该只减去 50!因此,当靠近底部关闭键盘时,它总是会重置到错误的固定位置。

  3. 我还认为您不能为此解决方案使用 onFocusonBlur 事件,因为这些事件仅在最初选择文本框以打开键盘时发生。您完全可以在不激活这些事件的情况下打开和关闭移动键盘,因此无法在此处使用它们。

我认为上述几点对于开发解决方案非常重要,因为它们一开始并不明显,但却阻碍了稳健解决方案的开发。

我不喜欢这个解决方案(间隔有点低效并且容易出现竞争条件),但我找不到任何更好的始终有效的解决方案。

关于javascript - 仅当不靠近 messages div 的底部时,保持滚动位置才有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59692647/

相关文章:

android - 选择元素在 Android 2.3.x 中不更新

android - React native/Trouble with AsyncStorage 获取项目

javascript - 使用 JavaScript 在 HTML 表单字段中传递二维数组

javascript - Xpath获取所有带有内部文本的链接

javascript - 来自 ajax 调用的 symfony 中的表单验证

javascript - 具有硬件加速 CSS 的 Canvas

javascript - 如果在服务器(nodeJS)上运行,此 JavaScript 代码的安全性如何?

android - 让拆分的 ActionBar 显示两倍的图标

css - 在 div 中鼠标悬停时使图像淡出

html - Chrome 为滚动条保留空间,即使它是隐藏的