保持滚动位置仅在不靠近消息div底部时有效 [英] Maintaining scroll position only works when not near the bottom of messages div

查看:53
本文介绍了保持滚动位置仅在不靠近消息div底部时有效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试模仿其他移动聊天应用程序,当您选择发送消息文本框并打开虚拟键盘时,最底部的消息仍在视图。似乎没有办法用CSS做到这一点,因此JavaScript resize (唯一的方法显然是发现键盘何时打开和关闭)是事件和手册。

I'm trying to mimic other mobile chatting apps where when you select the send-message textbox and it opens the virtual keyboard, the bottom-most message is still in view. There doesn't seem to be a way to do this with CSS amazingly, so JavaScript resize (only way to find out when the keyboard is opened and closed apparently) events and manual scrolling to the rescue.

有人提供了此解决方案,我找到了此解决方案,它们似乎都可以使用。

Someone provided this solution and I found out this solution, which both seem to work.

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

Except in one case. For some reason, if you are within MOBILE_KEYBOARD_HEIGHT (250 pixels in my case) pixels of the bottom of the messages div, when you close the mobile keyboard, something strange happens. With the former solution, it scrolls to the bottom. And with the latter solution, it instead scrolls up MOBILE_KEYBOARD_HEIGHT pixels from the bottom.

如果您在此上方滚动高度,以上提供的两种解决方案均能完美工作。

If you are scrolled above this height, both solutions provided above work flawlessly. It's only when you are near the bottom that they have this minor issue.

我想也许这只是我的程序导致了一些奇怪的流浪代码,但不是,我甚至复制了一个小提琴,它有这个确切的问题。我很抱歉使调试变得如此困难,但是如果您转到 https://jsfiddle.net/t596hy8d/ 6 / show (显示后缀提供全屏模式),您应该可以看到相同的行为。

I thought maybe it was just my program causing this with some weird stray code, but no, I even reproduced a fiddle and it has this exact issue. My apologies for making this so difficult to debug, but if you go to https://jsfiddle.net/t596hy8d/6/show (the show suffix provides a full-screen mode) on your phone, you should be able to see the same behavior.

该行为是,如果您向上滚动足够,则打开和关闭键盘将保持该位置。但是,如果您在底部的 MOBILE_KEYBOARD_HEIGHT 像素内关闭键盘,则会发现它滚动到底部。

That behavior being, if you scroll up enough, opening and closing the keyboard maintains the position. However, if you close the keyboard within MOBILE_KEYBOARD_HEIGHT pixels of the bottom, you'll find that it scrolls to the bottom instead.

是什么导致了这个原因?

此处的代码复制:

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>

推荐答案

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

I have finally found a solution that actually works. Although it may not be ideal, it actually works in all cases. Here is the code:

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

我沿途遇到的一些顿悟:

Some epiphanies I had along the way:


  1. 关闭虚拟键盘时,滚动事件在调整大小之前立即发生事件。这似乎仅在关闭键盘而不是在打开键盘时发生。 是您无法使用 scroll 事件设置 pxFromBottom 的原因,因为如果您在底部附近,它将在 scroll 事件中将自身设置为0,恰好在 resize 事件之前,使计算混乱

  1. When closing the virtual keyboard, a scroll event occurs instantly before the resize event. This seems to only happen when closing the keyboard, not opening it. This is the reason you cannot use the scroll event to set pxFromBottom, because if you are near the bottom it will set itself to 0 in the scroll event right before the resize event, messing up the calculation.

为什么所有解决方案在接近消息div底部时都遇到困难的另一个原因有点棘手。例如,在我的调整大小解决方案打开或关闭虚拟键盘时,我只需在 scrollTop 上加上或减去250(移动键盘高度)。除了靠近底部,这非常有效。为什么?因为假设您距底部50像素,然后关闭键盘。它会从 scrollTop (键盘高度)中减去250,但只能减去50!因此,在关闭靠近底部的键盘时,它将始终重置为错误的固定位置。

Another reason why all the solutions had difficulty near the bottom of the messages div is a bit tricky to understand. For example, in my resize solution I just add or subtract 250 (mobile keyboard height) to scrollTop when opening or closing the virtual keyboard. This works perfectly except near the bottom. Why? Because let's say you are 50 pixels from the bottom and close the keyboard. It will subtract 250 from scrollTop (the keyboard height), but it should only subtract 50! So it will always reset to the wrong fixed position when closing the keyboard near the bottom.

我也相信您不能使用 onFocus onBlur 事件,因为这些事件仅在最初选择文本框打开键盘时发生。您完全可以在不激活这些事件的情况下打开和关闭移动键盘,因此,它们无法在此处使用。

I also believe you cannot use onFocus and onBlur events for this solution, because those only occur when initially selecting the textbox to open the keyboard. You are perfectly able to open and close the mobile keyboard without activating these events, and as such, they are not able to used here.

我相信以上几点对开发解决方案很重要,因为它们起初并不明显,但会阻止开发可靠的解决方案。

I believe the above points are important to developing a solution, because they are non-obvious at first, but prevent a robust solution from developing.

I不喜欢这种解决方案(时间间隔效率低下并且容易出现竞争状况),但是我找不到能始终有效的更好的方法。

I don't like this solution (interval is a bit inefficient and prone to race conditions), but I cannot find anything better that always works.

这篇关于保持滚动位置仅在不靠近消息div底部时有效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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