使用Chrome和平滑滚动时出现奇怪的滚动行为。

3
我正在编写一个虚拟滚动库,遇到了一个奇怪的问题,只出现在Chrome中,并且禁用Chrome标志中的平滑滚动可以修复它。其中一部分逻辑是使用一个不可见的div来拉伸容器,并在向上滚动时获取一些新数据,然后将其滚回旧的顶部。然而,在启用平滑滚动的chrome浏览器中,似乎对scrollTop的更改不会立即应用,因此会获取多个数据并且滚动位置不正确。
我正在Linux上使用Chrome 84.0.4147.105-1,并在Windows上进行了相同结果的测试。有时很难触发该问题,最安全的方法是在靠近顶部的滚动条处拖动而不触发提取并向上滚动。然后,您会发现控制台值从0跳到900(向下滚动),然后变成一个小数(为什么?)并再次触发提取。

const container = document.getElementById('container')
const scroller = document.getElementById('scroller')

let height = 0
let isFetching = false
const fetchData = h => {
    if (isFetching) return
    isFetching = true
    setTimeout(() => {
        height += h
        scroller.style.height = height + 'px'
        container.scrollTop += h
        isFetching = false
    }, 50)
}

fetchData(800)

container.addEventListener('scroll', ev => {
    const top = ev.target.scrollTop
    console.log(top)
    if (top <= 50) {
        fetchData(800)
    }
})
#container {
    height: 200px;
    width: 500px;
    background-color: blue;
    overflow: auto;
}

#scroller {
    width: 100%;
}
<div id="container">
     <div id="scroller"></div>
</div>


这真的是一个相当丑陋的解决方案。我无法复现您所看到的确切问题,但考虑到您的超时函数将进一步引发滚动事件,我不会真正期望它能够可靠地运行。 - Tom Mettam
我已向chrome bugs报告了。 - Austaras
1个回答

0
一个临时的(非常不优雅的)解决方案是将fetchData更改为
const fetchData = h => {
    if (isFetching) return
    isFetching = true
    setTimeout(() => {
        height += h
        scroller.style.height = height + 'px'
        container.scrollTop += h
        isFetching = false
        setTimeout(() => container.scrollTop += h, 200)
    }, 50)
}

在短暂的延迟后再次滚动


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接