大量 DIV 时调整大小性能缓慢

问题描述 投票:0回答:2

我为一个小型益智游戏显示了一个点网格。 该脚本还不太正确,但这不是问题所在。

问题是对于所有这些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;
}

html css browser resize
2个回答
0
投票

确实有一个限制,这只是谷歌的一个建议,以避免过大的 DOM 大小。但是要很多div会对性能有很大的影响。 Lighouse 建议最多只有 1400 个节点。根据我的经验,具有超过 2k 个节点的网页可以正常工作。 但是过量会明显降低性能。 每个用户的确切节点数量会有所不同,之后性能会变慢。

https://developer.chrome.com/docs/lighthouse/performance/dom-size/

如果你想绘制这样的交互式背景,我建议你看看如何绘制 Canvas。作为一种替代方法,webgl 提供了为您的游戏利用增强渲染质量的能力。


0
投票

在没有任何图形库的情况下尝试这段代码

<!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>
全屏运行此代码,但它在 three.js 中。很多人会推荐 three.js,因为 three.js 是经过优化的,它非常棒,你可以用 three.js 做什么我的其他选择是使用 webgl,但即使对于我的水平来说它也非常先进。
<!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>

© www.soinside.com 2019 - 2024. All rights reserved.