Javascript 单个页面上有1000个DOM元素

Javascript 单个页面上有1000个DOM元素,javascript,html,dom,html5-canvas,Javascript,Html,Dom,Html5 Canvas,对于一个大的“文本地图”项目,我需要有1000多个文本输入。 单击并拖动时,可以“平移”显示区域。 但是性能非常差(在Firefox和Chrome上):渲染1000多个DOM元素一点也不快 当然,另一个性能更好的解决方案是:在上工作,将文本渲染为位图,每次我们要编辑文本时,让我们显示一个唯一的DOM,它将消失编辑完成的内容,并再次将文本渲染为位图它可以工作(我目前正朝着这个方向努力),但它需要更多的代码才能在画布上进行编辑 问题:有没有可能提高在HTML页面上呈现1000多个DOM元素的性能,这

对于一个大的“文本地图”项目,我需要有1000多个文本输入。 单击并拖动时,可以“平移”显示区域。

但是性能非常差(在Firefox和Chrome上):渲染1000多个DOM元素一点也不快

当然,另一个性能更好的解决方案是:在
上工作,将文本渲染为位图,每次我们要编辑文本时,让我们显示一个唯一的DOM
,它将消失编辑完成的内容,并再次将文本渲染为位图它可以工作(我目前正朝着这个方向努力),但它需要更多的代码才能在画布上进行编辑

问题:有没有可能提高在HTML页面上呈现1000多个DOM元素的性能,这样我就根本不需要使用

还是在平移包含1000多个DOM元素的页面时不可能获得良好的性能?


注:

1) 在这里的演示中,我使用了
,因为我需要多行输入+自动调整大小,但渲染性能与标准
相同*

2) 作为参考,这是我如何创建1000个文本元素的

for (i=0; i < 1000; i++)
{
  var blax = (Math.random()-0.5)*3000;
  var blay = (Math.random()-0.5)*3000;
  var tb = document.createElement('span');
  $(tb).data("x", blax / $(window).width());
  $(tb).data("y", blay / $(window).height());
  $(tb).data("size", 20 * currentzoom);
  tb.contentEditable = true;
  tb.style.fontFamily = 'arial';
  tb.style.fontSize = '20px';
  tb.style.position  = 'absolute';
  tb.style.top = blay + 'px';
  tb.style.left = blax + 'px';
  tb.innerHTML="newtext";
  document.body.appendChild(tb);
}
(i=0;i<1000;i++)的

{
var blax=(Math.random()-0.5)*3000;
var blay=(Math.random()-0.5)*3000;
var tb=document.createElement('span');
$(tb).data(“x”,blax/$(window.width());
$(tb).data(“y”,blay/$(window.height());
$(tb).数据(“大小”,20*currentzoom);
tb.contentEditable=true;
tb.style.fontFamily='arial';
tb.style.fontSize='20px';
tb.style.position='绝对';
tb.style.top=blay+'px';
tb.style.left=blax+'px';
tb.innerHTML=“newtext”;
文件.正文.附件(tb);
}

对于类似的内容,您可以使用document fragment,这些是不属于实际DOM树的DOM节点(更多信息可在此处找到),因此您可以在片段上执行所有设置,然后附加片段,这只会导致一个而不是1000个重新流动

下面是一个例子——快速检查运行时间,运行大约需要60-70毫秒

var currentzoom = 1;
var docFragment = document.createDocumentFragment();
var start = new Date();
for (i=0; i < 1000; i++)
{
  var blax = (Math.random()-0.5)*3000;
  var blay = (Math.random()-0.5)*3000;
  var tb = document.createElement('span');
  $(tb).data("x", blax / $(window).width());
  $(tb).data("y", blay / $(window).height());
  $(tb).data("size", 20 * currentzoom);
  tb.contentEditable = true;
  tb.style.fontFamily = 'arial';
  tb.style.fontSize = '20px';
  tb.style.position  = 'absolute';
  tb.style.top = blay + 'px';
  tb.style.left = blax + 'px';
  tb.innerHTML="newtext";
  docFragment.appendChild(tb);
}

document.body.appendChild(docFragment);

var end = new Date();
console.log(end-start)
更新2-

因此,为了提高性能,您可以缓存窗口的宽度和高度,使用vanilla for循环,使用vanilla js更改跨度的css。现在,每次重画(在chrome上)大约需要30-45毫秒()的时间,而我上面的更新大约需要80-100毫秒()

这里是更新后的重画

redraw = function (resize) {
    var spans = $("span").detach();
    var width = $(window).width();
    var height = $(window).height();

    for (var i = spans.length; i--;) {
        var span = $(spans[i]);
        var newx = Math.floor((span.data("x") - currentx) / currentzoom * width);
        var newy = Math.floor((span.data("y") - currenty) / currentzoom * height);
        if (resize) {
            displaysize = Math.floor(span.data("size") / currentzoom);
            if (displaysize) {
                span.css({
                    fontSize: displaysize
                });
                span.show();
            } else span.hide();
        }


        spans[i].style.top = newy + 'px',
        spans[i].style.left = newx + 'px'
    }

    $("body").append(spans);
};

片段示例-
var currentzoom=1;
var docFragment=document.createDocumentFragment();
var start=新日期();
变量位置=[]
var end=新日期();
console.log(结束-开始);
var currentx=0.0,
电流y=0.0,
currentzoom=1.0,
xold=0,
yold=0,
按钮=假;
对于(i=0;i<1000;i++){
var blax=(Math.random()-0.5)*3000;
var blay=(Math.random()-0.5)*3000;
var tb=document.createElement('span');
$(tb).data(“x”,blax/$(window.width());
$(tb).data(“y”,blay/$(window.height());
$(tb).数据(“大小”,20*currentzoom);
tb.contentEditable=true;
tb.style.fontFamily='arial';
tb.style.fontSize='20px';
tb.style.position='绝对';
tb.style.top=blay+'px';
tb.style.left=blax+'px';
tb.innerHTML=“newtext”;
docFragment.appendChild(tb);
}
document.body.appendChild(docFragment);
document.body.onclick=函数(e){
如果(e.target.nodeName=='SPAN'){
返回;
}
var tb=document.createElement('span');
$(tb).data(“x”,currentx+e.clientX/$(window).width()*currentzoom);
$(tb).data(“y”,currenty+e.clientY/$(window).height()*currentzoom);
$(tb).数据(“大小”,20*currentzoom);
tb.contentEditable=true;
tb.style.fontFamily='arial';
tb.style.fontSize='20px';
tb.style.backgroundColor=‘透明’;
tb.style.position='绝对';
tb.style.top=e.clientY+'px';
tb.style.left=e.clientX+'px';
文件.正文.附件(tb);
tb.focus();
};
document.body.onmousedown=函数(e){
按钮=真;
xold=e.clientX;
yold=e.clientY;
};
document.body.onmouseup=函数(e){
按钮=假;
};
重画=函数(调整大小){
var start=新日期();
变量span=$(“span”).detach();
变量宽度=$(窗口).width();
var height=$(window.height();
对于(var i=span.length;i--;){
var span=$(span[i]);
var newx=数学地板((跨度数据(“x”)-currentx)/currentzoom*宽度);
var newy=数学楼层((跨度数据(“y”)-当前y)/currentzoom*高度);
如果(调整大小){
displaysize=Math.floor(跨度数据(“尺寸”)/currentzoom);
如果(显示大小){
span.css({
fontSize:displaysize
});
span.show();
}else span.hide();
}
span[i].style.top=newy+'px',
span[i].style.left=newx+'px'
}
$(“正文”)。追加(跨度);
var end=新日期();
console.log(结束-开始);
};
document.body.onmousemove=函数(e){
如果(按钮){
currentx+=(xold-e.clientX)/$(window.width()*currentzoom;
currenty+=(yold-e.clientY)/$(window.height()*currentzoom;
xold=e.clientX;
yold=e.clientY;
重画(假);
}
};
$(函数(){
$('body')。在('mousedown','span',函数(事件)上{
if(event.which==3){
$(this.remove())
}
})
});
zoomcoef=函数(coef){
middlex=当前x+当前缩放/2
MIDLEY=当前Y+当前缩放/2
currentzoom*=coef
currentx=middlex-currentzoom/2
当前Y=中间Y-当前缩放/2
重画(真)
}
window.onkeydown=函数(事件){
if(event.ctrlKey&&event.keyCode==61){
zoomcoef(1/1.732);
event.preventDefault();
}
if(event.ctrlKey&&event.keyCode==169){
zoomcoef(1.732);
event.preventDefault();
}
if(event.ctrlKey&&event.keyCode==48){
zoomonwidget(1/1.732);
event.preventDefault();
}
};
html,正文{
身高:100%;
宽度:100%;
保证金:0;
填充:0;
飞越
redraw = function (resize) {
    var spans = $("span").detach();
    var width = $(window).width();
    var height = $(window).height();

    for (var i = spans.length; i--;) {
        var span = $(spans[i]);
        var newx = Math.floor((span.data("x") - currentx) / currentzoom * width);
        var newy = Math.floor((span.data("y") - currenty) / currentzoom * height);
        if (resize) {
            displaysize = Math.floor(span.data("size") / currentzoom);
            if (displaysize) {
                span.css({
                    fontSize: displaysize
                });
                span.show();
            } else span.hide();
        }


        spans[i].style.top = newy + 'px',
        spans[i].style.left = newx + 'px'
    }

    $("body").append(spans);
};
var texts=[];
var texts[0]={ text:'text#0',  x:100, y:100, width:35, height:20 }
var container = document.createElement("div"),
    wrapper = document.createElement("div"),
    dragging = false,
    offset = {x:0, y:0},
    previous = {x: 0, y:0};

container.style.position = "absolute";
wrapper.style.position = "relative";
container.appendChild(wrapper);
document.body.appendChild(container);

for (var i = 1000, span; i--;){
    span = document.createElement("span");
    span.textContent = "banana";
    span.style.position = "absolute";
    span.style.top = (Math.random() * 3000 - 1000 | 0) + 'px';
    span.style.left = (Math.random() * 3000 - 1000 | 0) + 'px';

    wrapper.appendChild(span);
}


// Don't attach events like this. 
// I'm only doing it for this proof of concept.

window.ondragstart = function(e){
    e.preventDefault();
}

window.onmousedown = function(e){
    dragging = true;
    previous = {x: e.pageX, y: e.pageY};
}

window.onmousemove = function(e){
    if (dragging){
        offset.x += e.pageX - previous.x;
        offset.y += e.pageY - previous.y;
        previous = {x: e.pageX, y: e.pageY};

        container.style.top = offset.y + 'px';
        container.style.left = offset.x + 'px';
    }
}

window.onmouseup = function(){
    dragging = false;
}