我的解决方案与您提出的解决方案相同,但增加了条件检查。以下是对我的解决方案的描述:
-
记录最后一个滚动位置
scrollTop
最后
clientHeight
属于
.messages
到
oldScrollTop
和
oldHeight
分别地
-
更新
oldScrollTop
和
旧高度
每次a
resize
发生在
window
并更新
oldScrollTop
每次a
scroll
发生在
.messages
-
什么时候?
窗口
缩小(当虚拟键盘显示时)
.messages
将自动缩回。预期行为是使最底层的内容
.messages
即使在以下情况下仍然可见
.messages
高度回缩。这要求我们手动调整滚动位置
scrollTop
属于
.messages
.
-
当虚拟键盘显示时,更新
scrollTop
属于
.messages
以确保最底部的部分
.messages
在其高度收缩发生之前,仍然可以看到
-
当虚拟键盘隐藏时,更新
scrollTop
属于
.messages
以确保最底部的部分
.messages
仍然是最底部的部分
.messages
高度膨胀后(除非膨胀不能向上发生;这发生在你几乎到达顶部时
.messages
)
是什么导致了这个问题?
我(最初可能有缺陷)的逻辑思维是:
调整大小
发生,
.messages
'高度变化,更新于
.messages
scrollTop
发生在我们的内部
调整大小
事件处理程序。然而,在
.messages
高度膨胀,a
纸卷
奇怪的是,事件发生在
调整大小
更奇怪的是
纸卷
事件
只有
当我们滚动到最大值以上时隐藏键盘时,就会发生这种情况
scrollTop
when的价值
.messages
未收回。就我而言,这意味着当我向下滚动时
270.334px
(最大值
scrollTop
之前
.messages
缩回)并隐藏键盘,这很奇怪
纸卷
之前
调整大小
事件发生并滚动您的
.messages
确切地说
270.334px
这显然打乱了我们上面的解决方案。
幸运的是,我们可以解决这个问题。我个人对此的推断
纸卷
之前
调整大小
事件的发生是因为
.messages
无法维持其
scrollTop
上方位置
270.334px
当它在高度上膨胀时
(这就是为什么我提到我最初的逻辑思维是有缺陷的;仅仅是因为没有办法
.messages
保持其
scrollTop
高于其最大值的位置)
因此,它立即设置
scrollTop
达到它可以给出的最大值(毫不奇怪,
270.334px
).
我们能做什么?
因为我们只更新
旧高度
在调整大小时,我们可以检查这个强制滚动(或者更准确地说,
调整大小
)如果发生这种情况,请不要更新
oldScrollTop
(因为我们已经处理过了
调整大小
!)我们只需要比较一下
旧高度
当前高度
纸卷
看看是否会发生这种强制滚动。这之所以有效,是因为
旧高度
不等于当前高度
纸卷
只有在以下情况下才是真的
调整大小
发生(这恰好是强制滚动发生的时候)。
这是代码
(in JSFiddle)
在......下面
window.onload = function(e) {
let messages = document.querySelector('.messages')
messages.scrollTop = messages.scrollHeight - messages.clientHeight
bottomScroller(messages);
}
function bottomScroller(scroller) {
let oldScrollTop = scroller.scrollTop
let oldHeight = scroller.clientHeight
scroller.addEventListener('scroll', e => {
console.log(`Scroll detected:
old scroll top = ${oldScrollTop},
old height = ${oldHeight},
new height = ${scroller.clientHeight},
new scroll top = ${scroller.scrollTop}`)
if (oldHeight === scroller.clientHeight)
oldScrollTop = scroller.scrollTop
});
window.addEventListener('resize', e => {
let newScrollTop = oldScrollTop + oldHeight - scroller.clientHeight
console.log(`Resize detected:
old scroll top = ${oldScrollTop},
old height = ${oldHeight},
new height = ${scroller.clientHeight},
new scroll top = ${newScrollTop}`)
scroller.scrollTop = newScrollTop
oldScrollTop = newScrollTop
oldHeight = 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>
在Firefox和Chrome移动版上进行了测试,它适用于这两种浏览器。