多按钮下载进度条适配问题:点击获取元素ID及对应文件
适配多按钮的下载进度条实现方案
要实现多按钮独立下载并对应各自进度条,核心是让每个下载按钮和其对应的进度条建立关联,通过事件委托处理所有按钮的点击,同时利用自定义属性存储每个按钮的专属下载路径。
1. HTML结构调整
每个下载项(按钮+进度条)放在独立容器中,给按钮统一类名,用data-file存储下载路径,确保按钮和进度条一一对应:
<html class="no-js" lang=""> <head> <script src="js/app.js" defer></script> <link rel="stylesheet" href="css/style.css"> </head> <body> <!-- 第一个下载项 --> <div class="download-item"> <button class="download-start-button" data-file="img/jdk-22_windows-x64_bin.exe">下载JDK</button> <div class="download-progress-bar__container"> <div class="download-progress-bar__progress"></div> </div> </div> <!-- 第二个下载项 --> <div class="download-item"> <button class="download-start-button" data-file="img/idea-2024.1.exe">下载IDEA</button> <div class="download-progress-bar__container"> <div class="download-progress-bar__progress"></div> </div> </div> </body> </html>
2. CSS样式适配
去掉单个ID的专属样式,改用类选择器适配多个下载项,同时优化进度条视觉效果:
html { height: 100%; } body { height: 100%; display: flex; flex-direction: column; gap: 20px; padding: 20px; margin: 0; } .download-start-button { background: #c50408; color: honeydew; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; } .download-start-button:disabled { background-color: rgb(39, 92, 74); cursor: not-allowed; } .download-item { display: flex; flex-flow: nowrap column; align-items: center; gap: 10px; } .download-progress-bar__container { width: 400px; height: 40px; border-radius: 10px; background: #eee; } .download-progress-bar__progress { background: linear-gradient(to right, rgba(255, 0, 0, 0), rgb(255, 0, 0)); border-radius: 10px; color: honeydew; display: flex; align-items: center; justify-content: center; width: 0; height: 100%; transition: width 0.2s ease; } .download-progress-bar__progress.error { background: linear-gradient(to right, rgba(138, 0, 226, 0), rgb(138, 0, 226)); }
3. JavaScript核心逻辑修改
使用事件委托监听所有下载按钮的点击,在处理函数中获取当前按钮的信息、对应进度条,执行独立的下载逻辑:
console.log('Initially ' + (window.navigator.onLine ? 'on' : 'off') + 'line'); window.addEventListener('online', () => console.log('Became online')); window.addEventListener('offline', () => console.log('Became offline')); // 事件委托:统一处理所有下载按钮的点击 document.body.addEventListener('click', async (e) => { // 只处理下载按钮的点击 if (!e.target.matches('.download-start-button')) return; const button = e.target; const fileToDownload = button.dataset.file; // 找到当前按钮对应的进度条(父容器内的进度条元素) const progressElem = button.closest('.download-item').querySelector('.download-progress-bar__progress'); // 避免重复点击 if (button.disabled) return; // 初始化状态 button.disabled = true; progressElem.classList.remove('error'); progressElem.textContent = ''; progressElem.style.width = '0%'; const dataChunks = []; try { const response = await fetch(`/${fileToDownload}`); if (!response.ok) throw new Error('网络请求失败'); const reader = response.body.getReader(); const totalSize = Number(response.headers.get('content-length')); let totalSizeDownloaded = 0; // 分段读取下载数据 async function readData() { const result = await reader.read(); if (result.value) { dataChunks.push(result.value); totalSizeDownloaded += result.value.length; const percentage = Math.floor((totalSizeDownloaded / totalSize) * 100); console.log(`${totalSizeDownloaded}/${totalSize} (${percentage}%)`); progressElem.textContent = `${percentage}%`; progressElem.style.width = `${percentage}%`; } if (!result.done) await readData(); } await readData(); // 生成下载链接并触发下载 const downloadAnchor = document.createElement('a'); const blob = new Blob(dataChunks); downloadAnchor.href = URL.createObjectURL(blob); // 只保留文件名作为下载文件名 downloadAnchor.download = fileToDownload.split('/').pop(); document.body.appendChild(downloadAnchor); downloadAnchor.click(); document.body.removeChild(downloadAnchor); // 释放Blob URL,避免内存泄漏 URL.revokeObjectURL(downloadAnchor.href); console.log('下载完成'); } catch (err) { console.error('下载错误:', err); progressElem.textContent = '下载失败'; progressElem.classList.add('error'); } finally { // 恢复按钮状态 button.disabled = false; } });
关键改动说明
- 事件委托:通过父元素统一监听点击,无需给每个按钮单独绑定事件,支持动态添加按钮的场景。
- 元素关联:用
closest('.download-item')定位当前按钮所在容器,确保每个按钮对应自己的进度条。 - 自定义属性:
data-file存储每个按钮的下载路径,避免硬编码,扩展性更强。 - 内存优化:下载完成后调用
URL.revokeObjectURL释放Blob资源,防止内存泄漏。 - 异步简化:改用
async/await替代链式Promise,代码更易读维护。
内容的提问来源于stack exchange,提问作者AetherxMana
相关产品推荐
相关产品推荐

