Javascript 仅当不在messages div的底部时,保持滚动位置才起作用

Javascript 仅当不在messages div的底部时,保持滚动位置才起作用,javascript,android,html,css,reactjs,Javascript,Android,Html,Css,Reactjs,我试图模仿其他移动聊天应用程序,当你选择发送消息文本框并打开虚拟键盘时,最底层的消息仍在视图中。令人惊讶的是,CSS似乎没有办法做到这一点,所以JavaScriptresize(确定键盘何时打开和关闭的唯一方法)事件和手动滚动来拯救 有人提供了,我发现了,这两种方法似乎都有效 只有一个例外。出于某种原因,如果您在messages div底部的MOBILE\u KEYBOARD\u HEIGHT(在我的例子中为250像素)像素范围内,当您关闭移动键盘时,会发生一些奇怪的情况。使用前一种解决方案,它

我试图模仿其他移动聊天应用程序,当你选择
发送消息
文本框并打开虚拟键盘时,最底层的消息仍在视图中。令人惊讶的是,CSS似乎没有办法做到这一点,所以JavaScript
resize
(确定键盘何时打开和关闭的唯一方法)事件和手动滚动来拯救

有人提供了,我发现了,这两种方法似乎都有效

只有一个例外。出于某种原因,如果您在messages div底部的
MOBILE\u KEYBOARD\u HEIGHT
(在我的例子中为250像素)像素范围内,当您关闭移动键盘时,会发生一些奇怪的情况。使用前一种解决方案,它会滚动到底部。使用后一种解决方案,它会从底部向上滚动
MOBILE\u KEYBOARD\u HEIGHT
像素

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

我想可能是我的程序用一些奇怪的杂散代码造成了这种情况,但不,我甚至复制了一把小提琴,它有这个确切的问题。很抱歉,这使得调试变得如此困难,但是如果您在手机上转到(显示后缀提供全屏模式),您应该能够看到相同的行为

如果向上滚动足够多,打开和关闭键盘可以保持该位置。但是,如果在底部的
MOBILE\u keyboard\u HEIGHT
像素范围内关闭键盘,您会发现它会滚动到底部

这是什么原因造成的

此处代码复制:

window.onload=函数(e){
document.querySelector(“.messages”).scrollTop=10000;
底部滚动条(document.querySelector(“.messages”);
}
功能底部滚动条(滚动条){
让scrollBottom=scroller.scrollHeight-scroller.scrollTop-scroller.clientHeight;
scroller.addEventListener('scroll',()=>{
scrollBottom=scroller.scrollHeight-scroller.scrollTop-scroller.clientHeight;
});   
addEventListener('resize',()=>{
scroller.scrollTop=scroller.scrollHeight-scrollBottom-scroller.clientHeight;
scrollBottom=scroller.scrollHeight-scroller.scrollTop-scroller.clientHeight;
});
}
.container{
宽度:400px;
高度:87vh;
边框:1px实心#333;
显示器:flex;
弯曲方向:立柱;
}
.留言{
溢出y:自动;
身高:100%;
}
.发送消息{
宽度:100%;
显示器:flex;
弯曲方向:立柱;
}

你好1
你好2
你好3
你好4
你好5
你好6
你好7
你好8
你好9
你好10
你好11
你好12
你好13
你好14
你好15
你好16
你好17
你好18
你好19
你好20
你好21
你好22
你好23
你好24
你好25
你好26
你好27
你好28
你好29
你好,30岁
你好31
你好32
你好33
你好34
你好35
你好36
你好37
你好38
你好39

我终于找到了一个切实可行的解决方案。虽然它可能并不理想,但实际上它在所有情况下都有效。代码如下:

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;
  });
}
一路上我有一些顿悟:

  • 关闭虚拟键盘时,
    滚动
    事件会在
    调整大小
    事件之前立即发生。这似乎只发生在关闭键盘时,而不是打开键盘时。这就是为什么您不能使用
    滚动
    事件来设置
    pxFromBottom
    ,因为如果您接近底部,它将在
    滚动
    事件中在
    调整大小
    事件之前将自身设置为0,从而扰乱计算

  • 所有解决方案在接近messages div底部时遇到困难的另一个原因有点难以理解。例如,在中,在打开或关闭虚拟键盘时,我只需将250(移动键盘高度)加上或减去
    scrollTop
    。除了靠近底部外,这项功能非常有效。为什么?因为假设你离底部50像素,然后关闭键盘。它将从
    scrollTop
    (键盘高度)中减去250,但它应该只减去50!因此,当关闭底部附近的键盘时,它总是会重置到错误的固定位置

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

  • 我相信以上几点对于开发解决方案很重要,因为它们在一开始并不明显,但会妨碍开发健壮的解决方案


    我不喜欢这个解决方案(interval有点低效,容易出现竞争条件),但我找不到更好的解决方案。

    我的解决方案与您建议的解决方案相同,只是增加了条件检查。以下是对我的解决方案的描述:

    • 分别将
      的最后一个滚动位置
      scrollTop
      和最后一个
      clientHeight
      记录到
      oldScrollTop
      oldHeight
    • 每次
      窗口
      上发生
      调整大小
      时更新
      oldcollScrollTop
      oldHeight
      ,每次
      上发生
      滚动时更新
      oldcollScrollTop
      。消息
    • 窗口
      缩小时(当虚拟键盘显示时),
      消息
      的高度将自动收缩。预期的行为是使
      .messages
      的最底层内容即使在
      .messages
      高度缩回时仍可见。这需要我们手动调整
      消息的滚动位置
      滚动顶部
    • 当虚拟