我正在尝试创建一种虚拟滚动机制,以使大型列表的DOM保持明亮。这个想法是可以从dom中删除主div中不可见的内容(可见视口之前/之后的内容),并替换为用作分隔符的空div。有一个带滚动条的div,它包含3个div:
该代码段显示了具有1000行的虚拟滚动。这是我的真实代码来说明这一点的最小示例。每10行被视为一个“页面”,并且每行都被硬编码为100px的高度。我有一个onscroll处理程序,它将检查是否需要更新3个div以在div之前/之后调整大小并更改在中间div中呈现的行。当我们向下滚动之前div的高度将增加而之后div的高度将缩小(这些div均为空且主要是间隔div,因此滚动条可以正常工作)。
这是问题所在。当我按下向下箭头一次以滚动时,它实际上会触发几次onscroll事件以平滑滚动(运行该代码段并向下按下箭头一次-您将看到滚动顶部一次变化几次,只有几个像素)。那也行。但是,当我到达“页面”边界并调整div之前/中间/之后时,似乎取消了后续滚动。因此,当我到达边界时,它不会滚动全部数量,看起来非常生涩。可以说该事件应针对1px,3px,5px,6px,10px触发5次,总计25px。对于1px,它将仅触发一次,随后的滚动将被取消。我猜是因为我正在修改div的内容?
如果按住向下箭头键相当平滑,但每10行仍然会出现轻微的延迟。
有什么想法可以使滚动更加流畅?
$( document ).ready(function() {
var ROW_HEIGHT = 100;
var PAGE_COUNT = 10;
var data = [];
for(var i = 0; i < 1000; i++){
data[data.length] = "index " + i;
}
function min(n,min){
return n < min? min:n;
}
function log(msg){
var logger=$("#logger")[0];
$(logger).append("<div>"+msg+"</div>")
logger.scrollTop = logger.scrollHeight;
}
var scrollInfo = {};
function virtualScroll(){
var scrollTop = $("#scrollbarWrapper").scrollTop();
log("scrollTop:"+scrollTop);
var topRow = Math.floor(scrollTop/ROW_HEIGHT);
var topPageRow = topRow-topRow%PAGE_COUNT;
var beforeRows = min(topPageRow-PAGE_COUNT,0);
var middleRows = 30;
var afterRows = data.length - middleRows - beforeRows;
if (scrollInfo != null && (scrollInfo.beforeRows == beforeRows && scrollInfo.middleRows == middleRows && scrollInfo.afterRows == afterRows )){
return;
}
log("=====ADJUSTING=DIVS=====");
scrollInfo = {beforeRows:beforeRows,middleRows:middleRows,afterRows:afterRows};
$(".middle").empty();
for (var i = beforeRows; i < beforeRows+middleRows; i++){
$(".middle").append("<div class='row'>"+data[i]+"</div>");
}
$(".before").outerHeight(beforeRows*ROW_HEIGHT);
$(".after").outerHeight(afterRows*ROW_HEIGHT);
$("#scrollbarWrapper").scrollTop(scrollTop);
$(".middle").focus();
}
virtualScroll();
$("#scrollbarWrapper").on("scroll",virtualScroll);
});
#scrollbarWrapper{
display:inline-block;
width:500px;
height:500px;
overflow:auto;
border:1px solid black;
}
.row{
display:inline-block;
height:100px;
width:100%;
border:1px solid black;
box-sizing:border-box;
}
#logger{
display:inline-block;
height:500px;
/*width:500px;*/
overflow:auto;
border:1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="scrollbarWrapper" class="scrollbarWrapper">
<div class="before" tabindex="0"></div>
<div class="middle" tabindex="0"></div>
<div class="after" tabindex="0"></div>
</div>
<div id="logger"></div>
答案 0 :(得分:1)
所以我发现,修改滚动条的任何内容都将停止滚动惯性。我重新设计了整个组件,以便避免设置滚动条。相反,我只是更新div之前和之后,以确保视口中的内容正确保留在视口中。我还发现,当我在滚动顶部上方的dom中添加任何内容时,会导致滚动顶部发生变化,这就是为什么我在示例代码中有一行代码来调整滚动顶部。现在,我按正确的顺序进行操作,并且在添加新内容之前要在div之前缩小。