虚拟列表

40 阅读1分钟

示例:

5a9c82b3-83e1-4854-92ff-751db8047ff9.gif

<!DOCTYPE html>  

	<html lang="en">  

	<head>  

	    <meta charset="UTF-8">  

	    <meta name="viewport" content="width=device-width, initial-scale=1.0">  

	    <title>Virtual List</title>  

	    <link rel="stylesheet" href="styles.css">  

	</head>  

	<body>  

	    <div id="virtual-list-container" class="virtual-list-container">  

	        <div id="virtual-list" class="virtual-list"></div>  

	    </div>  

	    <script src="script.js"></script>  

	</body>  

	</html>

body {  
  font-family: Arial, sans-serif;  
}  

.virtual-list-container {  
  height: 400px; /* 固定高度 */  
  overflow-y: auto; /* 允许滚动 */  
  border: 1px solid #ccc;  
  position: relative;  
}  

.virtual-list {  
  position: absolute;  
  width: 100%;  
}  

.virtual-list-item {  
  height: 30px; /* 固定高度 */  
  line-height: 30px;  
  border-bottom: 1px solid #eee;  
  padding: 0 10px;  
  box-sizing: border-box;  
}

document.addEventListener('DOMContentLoaded', () => {  
  const itemHeight = 30; // 每个列表项的高度  
  const totalItems = 10000; // 总列表项数  
  const visibleItemCount = Math.ceil(400 / itemHeight); // 可见区域列表项数(视容器高度而定)  
  const buffer = 5; // 缓冲区大小  

  const listContainer = document.getElementById('virtual-list-container');  
  const virtualList = document.getElementById('virtual-list');  

  let startIndex = 0;  
  let endIndex = Math.min(startIndex + visibleItemCount + buffer * 2, totalItems);  

  const renderList = () => {  
      virtualList.innerHTML = '';  

      for (let i = startIndex; i < endIndex; i++) {  
          const listItem = document.createElement('div');  
          listItem.classList.add('virtual-list-item');  
          listItem.textContent = `Item ${i + 1}`;  
          listItem.style.transform = `translateY(${i * itemHeight}px)`;  
          // 使用 transform 而不是 top,以避免潜在的布局问题  
          virtualList.appendChild(listItem);  
      }  

      // 可选:为了优化性能,可以只更新可见范围内的 DOM 节点  
      // 例如,可以保留之前渲染的节点,并只更新它们的内容或位置  
      // 而不是每次都重新创建所有节点  
  };  

  const updateList = () => {  
      const scrollTop = listContainer.scrollTop;  
      startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - buffer);  
      endIndex = Math.min(startIndex + visibleItemCount + buffer * 2, totalItems);  
      renderList();  
  };  

  listContainer.addEventListener('scroll', updateList);  

  // 初始渲染  
  renderList();  
});