我为一个小型益智游戏显示了一个点网格。 该脚本还不太正确,但这不是问题所在。
问题是对于所有这些div,调整浏览器窗口的大小非常缓慢。尽管没有在调整大小时重新绘制/重新定位元素之类的事情。
在 Safari 和 Chrome 中都试过了。 也用
grid
尝试过,结果与绝对定位相同。
需要一个大窗口来生成足够的 div(~5000)来显示问题。
难道我们不应该有这么多 div 吗?有没有办法优化这个?也许是拥有大量元素的替代解决方案?
使用 three.js 感觉对我想要完成的事情来说太过分了。
谢谢。
编辑:这是一个 JSBin 示例,您可以在其中尝试最大化窗口(然后重新运行)以使问题显现。
alert
显示生成的 div 的数量。 https://jsbin.com/zurojakese/edit?output.
let size = 10
let gap = 10
let cols = (window.innerWidth - gap) / (size + gap)
let rows = (window.innerHeight - gap) / (size + gap)
let col = 0
let row = 0
for (let i = 0; i < cols * rows; i++) {
let div = document.createElement('div')
document.body.appendChild(div)
div.style.top = gap + row * (gap + size) + 'px'
div.style.left = (row % 2 == 0 ? gap : 0) + gap + col * (gap + size) + 'px'
div.style.animationDelay = (0.25 * i) + 's'
col += 1
if (col > cols) {
col = 0;
row += 1
}
}
div {
position: absolute;
background: #adadad;
width: 10px;
height: 10px;
border-radius: 5px;
}
确实有一个限制,这只是谷歌的一个建议,以避免过大的 DOM 大小。但是要很多div会对性能有很大的影响。 Lighouse 建议最多只有 1400 个节点。根据我的经验,具有超过 2k 个节点的网页可以正常工作。 但是过量会明显降低性能。 每个用户的确切节点数量会有所不同,之后性能会变慢。
https://developer.chrome.com/docs/lighthouse/performance/dom-size/
如果你想绘制这样的交互式背景,我建议你看看如何绘制 Canvas。作为一种替代方法,webgl 提供了为您的游戏利用增强渲染质量的能力。
在没有任何图形库的情况下尝试这段代码
<!DOCTYPE html>
<html>
<head>
<title>Grid of dots</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
div {
position: absolute;
background: #adadad;
width: 10px;
height: 10px;
border-radius: 5px;
}
</style>
</head>
<body>
<script>
let dotsContainer = document.createElement('div');
document.body.appendChild(dotsContainer);
let dots = [];
function generateDots() {
let size = 10;
let gap = 10;
let cols = Math.floor((window.innerWidth - gap) / (size + gap));
let rows = Math.floor((window.innerHeight - gap) / (size + gap));
let col = 0;
let row = 0;
for (let i = 0; i < cols * rows; i++) {
let div = document.createElement('div');
dotsContainer.appendChild(div);
dots.push(div);
div.style.top = gap + row * (gap + size) + 'px';
div.style.left = (row % 2 == 0 ? gap : 0) + gap + col * (gap + size) + 'px';
div.style.animationDelay = (0.25 * i) + 's';
col += 1;
if (col > cols) {
col = 0;
row += 1;
}
}
}
function removeDots() {
dots.forEach((div) => dotsContainer.removeChild(div));
dots = [];
}
window.addEventListener('resize', () => {
removeDots();
generateDots();
});
generateDots();
let x = dots.length;
alert(x);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>Grid of dots in Three.js</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
let camera, scene, renderer;
let dots = [];
init();
animate();
function init() {
// Create a camera
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 0, 0, 500 );
// Create a scene
scene = new THREE.Scene();
// Create a renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// Generate the dots
generateDots();
}
function animate() {
requestAnimationFrame( animate );
// Rotate the dots delete this if you dont want balls rotate
dots.forEach((dot) => {
dot.rotation.x += 0.04;
dot.rotation.y += 0.02;
});
renderer.render( scene, camera );
}
function generateDots() {
let size = 10;
let gap = 10;
let cols = Math.floor((window.innerWidth - gap) / (size + gap));
let rows = Math.floor((window.innerHeight - gap) / (size + gap));
let col = 0;
let row = 0;
for (let i = 0; i < cols * rows; i++) {
let geometry = new THREE.CircleGeometry( size, 16 );
let material = new THREE.MeshBasicMaterial( { color: 0xadadad } );
let mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
dots.push( mesh );
mesh.position.x = (row % 2 == 0 ? gap : 0) + gap + col * (gap + size) - window.innerWidth / 2;
mesh.position.y = gap + row * (gap + size) - window.innerHeight / 2;
col += 1;
if (col > cols) {
col = 0;
row += 1;
}
}
}
function removeDots() {
dots.forEach((dot) => scene.remove(dot));
dots = [];
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
removeDots();
generateDots();
});
</script>
</body>
</html>