我有一个包含两列的网页,一个带导航栏和页脚的标题。
左列用于列出三个不同标签中的项目。每个选项卡都包含其项目的类型。
右侧包含一个或多个地图以显示项目。
选择包含太多元素的选项卡时会出现问题。
它冻结了交互(突出显示,添加/删除DOM和动画),打破了它的响应能力。
即使它不是与所选标签的交互(即鼠标悬停在导航栏链接上)。
但是当所选标签的项目较少时,页面的响应能力很好。
我创建了一个spike solution来向您展示我在说什么。
请你记住,这是我问题的一个简单版本。这只是一个虚拟的例子来陈述我的案例。
$('#nav-tabs a').click(function (e) {
e.preventDefault()
$(this).tab('show')
});
$('#addBox').on('click', function () {
$("#content").append("<div class='box pull-left'></div>");
});
$('#newPapper').on('click', function () {
$("#content").empty();
});
$('#addOne').on('click', function () {
$("#home div.panel-default").append(createContactDom());
});
$('#addThousand').on('click', function () {
var dom = "";
for(var i = 5000; i > 0; i--){
dom+=createContactDom();
}
$("#home div.panel-default").append(dom);
});
$('#clean').on('click', function () {
$("#home div.panel-default").empty();
});
function createContactDom(){
var age = Math.round(Math.random()*100);
var birthday = moment().subtract(age, 'years');
var isFemale = Math.random() > 0.4;
var nameIndex = Math.floor(Math.random() * names[isFemale ? "female" : "male"].length);
var surnameIndex = Math.floor(Math.random() * surnames.length)
var name = names[isFemale ? "female" : "male"][nameIndex] + " " + surnames[surnameIndex];
var html = '<div id="p' + birthday.format("X") + '" class="panel-heading">';
html += '<span class="fa-stack fa-lg custom-stack pull-left font-grey-gallery" >';
html += '<i class="fa fa-square-o fa-stack-2x"></i>';
html += '<i class="fa fa-user fa-stack-1x"></i>';
html += '</span>';
html += '<div class="pull-left">';
html += '<div class="title">';
html += '<span >' + name + '</span> ';
html += '</div>';
html += '<div class="sub-title">';
html += '<span title="' + (isFemale ? 'She': 'He') + ' was born on a ' + birthday.format('dddd') + ' at ' + birthday.format('HH:MM a') + '" class="badge pull-left" >' + birthday.format("YYYY/MM/DD") +'</span>';
html += '<span title="It is a ' + (isFemale ? 'female' : 'male') + '" class="badge pull-left ' + (isFemale ? 'female' : 'male') + '" >' + (isFemale ? 'Female' : 'Male') + '</span>';
html += '<div class="clearfix"></div>';
html += '</div>';
html += '</div>';
html += '<div class="pull-right actions">';
html += '<a id="d' + birthday.format("X") + '" title="Delete contact" class="fa fa-times fa-times-close" style="color: rgb(87, 142, 190);" onclick="deleteContact(this)"></a>';
html += '</div>';
html += '<div class="clearfix"></div>';
html += '</div>';
return html;
}
deleteContact = function(e){
$("#" + e.id.replace("d", "p")).remove();
}
var names = {
female: ["Maria","Leonor","Matilde","Beatriz","Carolina","Mariana","Ana","Inês","Margarida","Sofia"],
male: ["João", "Martim", "Rodrigo", "Santiago", "Francisco", "Afonso", "Tomás", "Miguel", "Guilherme", "Gabriel"]
}
var surnames = ["Silva", "Santos", "Ferreira", "Pereira", "Oliveira", "Costa", "Rodrigues", "Martins", "Jesus", "Sousa", "Fernandes", "Gonçalves", "Gomes", "Lopes", "Marques", "Alves", "Almeida", "Ribeiro", "Pinto", "Carvalho"]
.row{
height: 600px;
}
.col-sm-5,
.col-sm-7{
height: inherit;
}
.tab-content{
height: inherit;
overflow-y: auto;
}
button{
margin-top: 5px;
}
span.badge{
margin-right: 5px;
}
.badge{
background-color: #999 !important;
}
.badge.female{
background-color: pink !important;
}
.badge.male{
background-color: #1c90f3 !important;
}
#content{
height: inherit;
overflow-y: auto;
padding-top: 5px;
}
#content .box{
width: 100px;
height: 100px;
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div class="col-sm-5">
<ul class="nav nav-tabs" id="myTabs" role="tablist">
<li role="presentation" class="active">
<a href="#home" id="home-tab" role="tab" data-toggle="tab" aria-controls="home" aria-expanded="true">Contacts</a>
</li>
<li role="presentation" class="">
<a href="#profile" role="tab" id="profile-tab" data-toggle="tab" aria-controls="profile" aria-expanded="false">Problem?</a>
</li>
<li>
<button type="button" id="addOne" class="btn btn-sm">+</button>
<button type="button" id="addThousand" class="btn btn-sm btn-primary">+5k</button>
<button type="button" id="clean" class="btn btn-sm">clean</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade active in" role="tabpanel" id="home" aria-labelledby="home-tab">
<div class="panel panel-default" style="border-left: 3px solid rgb(87, 142, 190);" >
</div>
</div>
<div class="tab-pane fade" role="tabpanel" id="profile" aria-labelledby="profile-tab">
<h1>Problems to solve:</h1>
<ul>
<li>Adding 5k new contacts blocks the browser's page</li>
<li>Switching between the two tabs blocks the browser's page</li>
<li>Painting freezes when adding 5k new contacts</li>
</ul>
<p>Note: The problems get worse as may contacts you add...</p>
</div>
</div>
</div>
<div class="col-sm-7">
<button tyoe="button" id="addBox" class="btn btn-sm btn-primary">Paint</button>
<button tyoe="button" id="newPapper" class="btn btn-sm">New papper</button>
<div id="content"></div>
</div>
</div>
我已经在使用Chrome开发者工具捕获时间轴的操作。到目前为止,我可以看到,问题是jquery的布局渲染中的一些回流。
如何优化DOM操作以避免页面冻结?在我这样说之前,我可以告诉浏览器不要重绘左栏吗?
答案 0 :(得分:5)
为什么不对这样的大表使用虚拟滚动或无限滚动或分页,而不是在启动?
有很多例子: https://www.sitepoint.com/jquery-infinite-scrolling-demos/
将5k个物体放在一行中太多了,imo。
在你的情况下,你需要在堆栈/事件循环中拆分/中断dom操作循环以用于其他东西。
$('#addThousand').on('click', function () {
for(var i = 5000; i > 0; i--){
setTimeout( function() {
var dom=createContactDom();
$("#home div.panel-default").append(dom);
}, 0);
}
});
或事件:
$('#addThousand').on('click', function () {
for(var i = 5000; i > 0; i--){
setTimeout( function() {
var dom=createContactDom();
$("#home div.panel-default").append(dom);
}, i);
}
});
答案 1 :(得分:3)
fast interacting with large number of elements inside a container (DOM, javascript)
是的,我确实做了一些测试和研究......这引导我做到这一点。
你需要使用类似下面的东西。问题是display none和block会根据您隐藏/显示的数据量对dom性能产生影响。
解决这个问题的方法就是将其移出视野。这样,如果内容存在或不存在,dom就不必运行计算。因为从技术上讲,它从未离开这样做。向下是你需要实现自己的标签..苏打水说能够覆盖默认行为。
div {
position: relative;
left: 0px;
}
div.hide {
left: -4096px;
height: 0px;
}