<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>代码优化 - 虚拟滚动</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);min-height: 100vh;padding: 20px;}.container {max-width: 1200px;margin: 0 auto;background: white;border-radius: 15px;padding: 30px;box-shadow: 0 20px 60px rgba(0,0,0,0.3);}h1 {text-align: center;color: #333;margin-bottom: 10px;}.subtitle {text-align: center;color: #666;margin-bottom: 30px;}.demo-section {display: grid;grid-template-columns: 1fr 1fr;gap: 30px;margin-bottom: 30px;}.demo-box {border: 2px solid #e0e0e0;border-radius: 10px;padding: 20px;background: #f9f9f9;}.demo-box h3 {color: #667eea;margin-bottom: 15px;display: flex;align-items: center;gap: 10px;}.demo-box.bad {border-color: #ff6b6b;}.demo-box.good {border-color: #51cf66;}.demo-box.bad h3::before {content: '❌';}.demo-box.good h3::before {content: '✅';}.list-container {height: 400px;overflow-y: auto;border: 1px solid #ddd;border-radius: 8px;background: white;position: relative;}.list-item {padding: 15px;border-bottom: 1px solid #eee;display: flex;align-items: center;gap: 15px;transition: background 0.2s;}.list-item:hover {background: #f5f5f5;}.list-item .avatar {width: 40px;height: 40px;border-radius: 50%;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);display: flex;align-items: center;justify-content: center;color: white;font-weight: bold;flex-shrink: 0;}.list-item .content {flex: 1;}.list-item .name {font-weight: 600;color: #333;margin-bottom: 5px;}.list-item .email {color: #666;font-size: 14px;}.list-item .status {padding: 4px 12px;border-radius: 12px;font-size: 12px;font-weight: 500;}.list-item .status.online {background: #d4edda;color: #155724;}.list-item .status.offline {background: #f8d7da;color: #721c24;}.virtual-content {position: absolute;top: 0;left: 0;right: 0;}.controls {display: flex;gap: 10px;flex-wrap: wrap;margin-top: 15px;}button {padding: 10px 20px;border: none;border-radius: 5px;cursor: pointer;font-size: 14px;transition: all 0.3s;}.btn-primary {background: #667eea;color: white;}.btn-primary:hover {background: #5a6fd6;transform: translateY(-2px);}.btn-danger {background: #ff6b6b;color: white;}.btn-danger:hover {background: #fa5252;}.btn-success {background: #51cf66;color: white;}.btn-success:hover {background: #40c057;}.stats {display: grid;grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));gap: 15px;margin-top: 20px;}.stat-card {background: white;padding: 15px;border-radius: 8px;box-shadow: 0 2px 8px rgba(0,0,0,0.1);text-align: center;}.stat-card h4 {color: #666;font-size: 14px;margin-bottom: 10px;}.stat-value {font-size: 24px;font-weight: bold;color: #667eea;}.stat-value.high {color: #ff6b6b;}.stat-value.low {color: #51cf66;}.code-section {background: #f8f9fa;border-radius: 10px;padding: 20px;margin-top: 30px;}.code-section h3 {color: #333;margin-bottom: 15px;}pre {background: #2d2d2d;color: #f8f8f2;padding: 15px;border-radius: 8px;overflow-x: auto;font-size: 13px;line-height: 1.5;}.tips {background: #e7f3ff;border-left: 4px solid #667eea;padding: 15px;margin-top: 20px;border-radius: 0 8px 8px 0;}.tips h4 {color: #667eea;margin-bottom: 10px;}.tips ul {margin-left: 20px;color: #555;}.tips li {margin: 5px 0;}.performance-info {background: #fff3cd;border-left: 4px solid #ffc107;padding: 15px;margin-top: 15px;border-radius: 0 8px 8px 0;}.performance-info h4 {color: #856404;margin-bottom: 10px;}.performance-info p {color: #856404;font-size: 14px;line-height: 1.6;}</style></head><body><div class="container"><h1>代码优化 - 虚拟滚动</h1><p class="subtitle">虚拟滚动只渲染可视区域内的元素,大幅提升长列表性能</p><div class="demo-section"><div class="demo-box bad"><h3>普通滚动(全部渲染)</h3><div id="normalContainer" class="list-container"></div><div class="performance-info"><h4>⚠️ 性能问题</h4><p>渲染10000个DOM节点,导致页面卡顿、内存占用高</p></div><div class="controls"><button class="btn-danger" onclick="loadNormalList()">加载10000条数据</button><button class="btn-primary" onclick="clearNormal()">清空</button></div></div><div class="demo-box good"><h3>虚拟滚动(按需渲染)</h3><div id="virtualContainer" class="list-container"></div><div class="performance-info" style="background: #d4edda; border-color: #28a745;"><h4 style="color: #155724;">✅ 性能优化</h4><p>只渲染可视区域的元素,性能提升显著</p></div><div class="controls"><button class="btn-success" onclick="loadVirtualList()">加载10000条数据</button><button class="btn-primary" onclick="clearVirtual()">清空</button></div></div></div><div class="stats"><div class="stat-card"><h4>普通渲染DOM数量</h4><div id="normalDomCount" class="stat-value high">0</div></div><div class="stat-card"><h4>虚拟渲染DOM数量</h4><div id="virtualDomCount" class="stat-value low">0</div></div><div class="stat-card"><h4>DOM减少比例</h4><div id="domReduction" class="stat-value">0%</div></div><div class="stat-card"><h4>数据总量</h4><div id="totalData" class="stat-value">0</div></div></div><div class="code-section"><h3>代码实现</h3><pre><code>// 虚拟滚动实现class VirtualScroll {constructor(container, options = {}) {this.container = container;this.itemHeight = options.itemHeight || 70;this.totalItems = options.totalItems || 0;this.visibleCount = Math.ceil(container.offsetHeight / this.itemHeight) + 2;this.init();}init() {// 创建虚拟内容容器this.content = document.createElement('div');this.content.className = 'virtual-content';this.content.style.height = (this.totalItems * this.itemHeight) + 'px';this.container.appendChild(this.content);// 监听滚动事件this.container.addEventListener('scroll', () => {this.render();}, { passive: true });// 初始渲染this.render();}render() {const scrollTop = this.container.scrollTop;const startIndex = Math.floor(scrollTop / this.itemHeight);const endIndex = Math.min(startIndex + this.visibleCount, this.totalItems - 1);// 清空当前内容this.content.innerHTML = '';// 渲染可见区域的元素for (let i = startIndex; i <= endIndex; i++) {const item = this.createItem(i);item.style.position = 'absolute';item.style.top = (i * this.itemHeight) + 'px';item.style.left = '0';item.style.right = '0';this.content.appendChild(item);}}createItem(index) {const item = document.createElement('div');item.className = 'list-item';item.innerHTML = `<div class="avatar">${index + 1}</div><div class="content"><div class="name">用户 ${index + 1}</div><div class="email">user${index + 1}@example.com</div></div><div class="status ${index % 2 === 0 ? 'online' : 'offline'}">${index % 2 === 0 ? '在线' : '离线'}</div>`;return item;}setData(totalItems) {this.totalItems = totalItems;this.content.style.height = (this.totalItems * this.itemHeight) + 'px';this.render();}destroy() {this.container.removeEventListener('scroll', this.render);this.content.remove();}}// 使用示例const virtualScroll = new VirtualScroll(document.getElementById('container'), {itemHeight: 70,totalItems: 10000});</code></pre></div><div class="tips"><h4>虚拟滚动的优势</h4><ul><li><strong>大幅减少DOM节点</strong>:只渲染可视区域的元素,DOM节点数量大幅减少</li><li><strong>提升渲染性能</strong>:减少重排重绘,提升页面流畅度</li><li><strong>降低内存占用</strong>:DOM节点减少,内存占用显著降低</li><li><strong>支持海量数据</strong>:可以轻松处理数万甚至数十万条数据</li><li><strong>滚动流畅</strong>:滚动性能不受数据量影响</li></ul><h4>适用场景</h4><ul><li>长列表展示(用户列表、订单列表等)</li><li>数据表格(大量行数据)</li><li>聊天记录(历史消息)</li><li>时间轴(大量时间节点)</li><li>任何需要展示大量数据的场景</li></ul><h4>实现要点</h4><ul><li><strong>计算可视区域</strong>:根据容器高度和项目高度计算可见数量</li><li><strong>设置总高度</strong>:使用占位元素设置正确的滚动高度</li><li><strong>动态渲染</strong>:根据滚动位置动态渲染可见元素</li><li><strong>性能优化</strong>:使用passive事件监听器,避免阻塞滚动</li><li><strong>预加载</strong>:多渲染几个元素,避免滚动时出现空白</li></ul></div></div><script>let normalDomCount = 0;let virtualDomCount = 0;let totalDataCount = 0;// 普通滚动 - 渲染所有元素function loadNormalList() {const container = document.getElementById('normalContainer');clearNormal();const startTime = performance.now();const fragment = document.createDocumentFragment();for (let i = 0; i < 10000; i++) {const item = document.createElement('div');item.className = 'list-item';item.innerHTML = `<div class="avatar">${i + 1}</div><div class="content"><div class="name">用户 ${i + 1}</div><div class="email">user${i + 1}@example.com</div></div><div class="status ${i % 2 === 0 ? 'online' : 'offline'}">${i % 2 === 0 ? '在线' : '离线'}</div>`;fragment.appendChild(item);}container.appendChild(fragment);const endTime = performance.now();normalDomCount = 10000;totalDataCount = 10000;document.getElementById('normalDomCount').textContent = normalDomCount;document.getElementById('totalData').textContent = totalDataCount;updateStats();}// 虚拟滚动 - 只渲染可见元素function loadVirtualList() {const container = document.getElementById('virtualContainer');clearVirtual();const itemHeight = 70;const totalItems = 10000;const containerHeight = container.offsetHeight;const visibleCount = Math.ceil(containerHeight / itemHeight) + 2;// 创建虚拟内容容器const content = document.createElement('div');content.className = 'virtual-content';content.style.height = (totalItems * itemHeight) + 'px';container.appendChild(content);// 渲染函数function render() {const scrollTop = container.scrollTop;const startIndex = Math.floor(scrollTop / itemHeight);const endIndex = Math.min(startIndex + visibleCount, totalItems - 1);content.innerHTML = '';for (let i = startIndex; i <= endIndex; i++) {const item = document.createElement('div');item.className = 'list-item';item.style.position = 'absolute';item.style.top = (i * itemHeight) + 'px';item.style.left = '0';item.style.right = '0';item.innerHTML = `<div class="avatar">${i + 1}</div><div class="content"><div class="name">用户 ${i + 1}</div><div class="email">user${i + 1}@example.com</div></div><div class="status ${i % 2 === 0 ? 'online' : 'offline'}">${i % 2 === 0 ? '在线' : '离线'}</div>`;content.appendChild(item);}virtualDomCount = endIndex - startIndex + 1;document.getElementById('virtualDomCount').textContent = virtualDomCount;updateStats();}// 监听滚动事件container.addEventListener('scroll', render, { passive: true });// 初始渲染render();totalDataCount = 10000;document.getElementById('totalData').textContent = totalDataCount;}function clearNormal() {document.getElementById('normalContainer').innerHTML = '';normalDomCount = 0;document.getElementById('normalDomCount').textContent = 0;updateStats();}function clearVirtual() {const container = document.getElementById('virtualContainer');container.innerHTML = '';container.removeEventListener('scroll', () => {});virtualDomCount = 0;document.getElementById('virtualDomCount').textContent = 0;updateStats();}function updateStats() {if (normalDomCount > 0 && virtualDomCount > 0) {const reduction = ((normalDomCount - virtualDomCount) / normalDomCount * 100).toFixed(1);document.getElementById('domReduction').textContent = reduction + '%';}}</script></body></html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。