我正在尝试基于虚拟渲染概念渲染列表。我面临一些小问题,但他们并没有阻止这种行为。这是工作小提琴http://jsfiddle.net/53N36/9/,这是我的问题
我用700000件物品和70件镀铬物品进行了测试。以下是代码
(function () {
var list = (function () {
var temp = [];
for (var i = 0, l = 70; i < l; i++) {
temp.push("list-item-" + (i + 1));
}
return temp;
}());
function listItem(text, id) {
var _div = document.createElement('div');
_div.innerHTML = text;
_div.className = "listItem";
_div.id = id;
return _div;
}
var listHold = document.getElementById('listHolder'),
ht = listHold.clientHeight,
wt = listHold.clientWidth,
ele = listItem(list[0], 'item0'),
frag = document.createDocumentFragment();
listHold.appendChild(ele);
var ht_ele = ele.clientHeight,
filled = ht_ele,
filledIn = [0];
for (var i = 1, l = list.length; i < l; i++) {
if (filled + ht_ele < ht) {
filled += ht_ele;
ele = listItem(list[i], 'item' + i);
frag.appendChild(ele);
} else {
filledIn.push(i);
break;
}
}
listHold.appendChild(frag.cloneNode(true));
var elements = document.querySelectorAll('#listHolder .listItem');
function MouseWheelHandler(e) {
var e = window.event || e;
var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
console.log(delta);
//if(filledIn[0] != 0 && filledIn[0] != list.length){
if (delta == -1) {
var start = filledIn[0] + 1,
end = filledIn[1] + 1,
counter = 0;
if (list[start] && list[end]) {
for (var i = filledIn[0]; i < filledIn[1]; i++) {
if (list[i]) {
(function (a) {
elements[counter].innerHTML = list[a];
}(i));
counter++;
}
}
filledIn[0] = start;
filledIn[1] = end;
}
} else {
var start = filledIn[0] - 1,
end = filledIn[1] - 1,
counter = 0;
if (list[start] && list[end]) {
for (var i = start; i < end; i++) {
if (list[i]) {
(function (a) {
elements[counter].innerHTML = list[a];
}(i));
counter++;
}
}
filledIn[0] = start;
filledIn[1] = end;
}
}
//}
}
if (listHold.addEventListener) {
listHold.addEventListener("mousewheel", MouseWheelHandler, false);
listHold.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
} else listHold.attachEvent("onmousewheel", MouseWheelHandler);
}());
请在此建议我。
修改: 我再次尝试,我能够解决索引问题。 http://jsfiddle.net/53N36/26/ 但是如何根据当前显示的数组列表计算滚动位置。
答案 0 :(得分:9)
Is this the best method or any other?
我认为让这更容易的事情不是试图自己处理滚动
在 this fiddle 中,我展示了您可以让浏览器为您处理滚动,即使我们使用的是virtual rendering
。
使用.scrollTop
我检测浏览器认为用户正在查看的位置,并根据该内容绘制项目。
您会注意到,如果您将hidescrollbar
设置为false并且用户使用它进行滚动,我的方法仍可正常运行。
因此,calculate scroll position
您可以.scrollTop
使用.scrollTop
至于自定义滚动,只需确保影响#listHolder
的{{1}}并回忆refreshWindow()
来自FIDDLE的代码
(function () {
//CHANGE THESE IF YOU WANT
var hidescrollbar = false;
var numberofitems = 700000;
//
var holder = document.getElementById('listHolder');
var view = null;
//get the height of a single item
var itemHeight = (function() {
//generate a fake item
var div = document.createElement('div');
div.className = 'listItem';
div.innerHTML = 'testing height';
holder.appendChild(div);
//get its height and remove it
var output = div.offsetHeight;
holder.removeChild(div);
return output;
})();
//faster to instantiate empty-celled array
var items = Array(numberofitems);
//fill it in with data
for (var index = 0; index < items.length; ++index)
items[index] = 'item-' + index;
//displays a suitable number of items
function refreshWindow() {
//remove old view
if (view != null)
holder.removeChild(view);
//create new view
view = holder.appendChild(document.createElement('div'));
var firstItem = Math.floor(holder.scrollTop / itemHeight);
var lastItem = firstItem + Math.ceil(holder.offsetHeight / itemHeight) + 1;
if (lastItem + 1 >= items.length)
lastItem = items.length - 1;
//position view in users face
view.id = 'view';
view.style.top = (firstItem * itemHeight) + 'px';
var div;
//add the items
for (var index = firstItem; index <= lastItem; ++index) {
div = document.createElement('div');
div.innerHTML = items[index];
div.className = "listItem";
view.appendChild(div);
}
console.log('viewing items ' + firstItem + ' to ' + lastItem);
}
refreshWindow();
document.getElementById('heightForcer').style.height = (items.length * itemHeight) + 'px';
if (hidescrollbar) {
//work around for non-chrome browsers, hides the scrollbar
holder.style.width = (holder.offsetWidth * 2 - view.offsetWidth) + 'px';
}
function delayingHandler() {
//wait for the scroll to finish
setTimeout(refreshWindow, 10);
}
if (holder.addEventListener)
holder.addEventListener("scroll", delayingHandler, false);
else
holder.attachEvent("onscroll", delayingHandler);
}());
<div id="listHolder">
<div id="heightForcer"></div>
</div>
html, body {
width:100%;
height:100%;
padding:0;
margin:0
}
body{
overflow:hidden;
}
.listItem {
border:1px solid gray;
padding:0 5px;
width: margin : 1px 0px;
}
#listHolder {
position:relative;
height:100%;
width:100%;
background-color:#CCC;
box-sizing:border-box;
overflow:auto;
}
/*chrome only
#listHolder::-webkit-scrollbar{
display:none;
}*/
#view{
position:absolute;
width:100%;
}