如何渲染数组内的歌曲列表并自动获取对应音频时长
问题描述
需要将数组中存储的所有歌曲展示为列表形式,同时获取每个列表项对应的音频时长,咨询该功能是否支持自动实现,还是必须手动将duration字段添加到数组中。当前已编写的初始代码如下:
let tracks = [ { name: "Song 1", artist: "Monica", path: "..song1.mp3", }, { name: "Song 2", artist: "Carol", path: "..song2.mp3" }, { name: "Song 3", artist: "Sam", path: "..song3.mp3" } ]; let list = "<ul>"; for (let i = 0; i < tracks.length; i++) { list += '<li>'; list += '<div class="name">' + tracks[i].name + '</div>'; list += '<div class="artist">' + tracks[i].artist + '</div>'; list += '<div class="duration">XX:XX</div>'; list += '<a href="' + tracks[i].path + '">Download</a>'; list += '</li>'; } // 此处存在语法错误:同一作用域重复用let声明list变量 let list = "</ul>"; playlist.innerHTML = list;
解答
- 不需要手动提前给数组硬编码
duration字段,可通过浏览器原生HTMLAudioElementAPI自动读取音频元数据获取时长。 - 音频元数据加载是异步过程,无法通过同步拼接字符串的方式直接在初始渲染时拿到时长,可先渲染带占位符的列表,等元数据加载完成后再更新对应DOM节点的时长内容。
- 原代码存在语法问题:拼接闭合
</ul>标签时直接对已有list变量做追加赋值即可,不需要重复声明变量。
修正后可运行实现代码
const tracks = [ { name: "Song 1", artist: "Monica", path: "../song1.mp3", }, { name: "Song 2", artist: "Carol", path: "../song2.mp3" }, { name: "Song 3", artist: "Sam", path: "../song3.mp3" } ]; // 时长格式化工具:秒转MM:SS格式,不足两位自动补零 const formatDuration = (seconds) => { const min = Math.floor(seconds / 60); const sec = Math.floor(seconds % 60); return `${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`; }; // 先渲染基础列表结构 let listStr = "<ul>"; tracks.forEach((track, index) => { listStr += `<li data-index="${index}">`; listStr += `<div class="name">${track.name}</div>`; listStr += `<div class="artist">${track.artist}</div>`; // 给时长节点加专属标识,方便后续异步更新内容 listStr += `<div class="duration" data-duration-role="${index}">加载中...</div>`; listStr += `<a href="${track.path}" download>Download</a>`; listStr += `</li>`; // 异步加载音频元数据获取时长 const audio = new Audio(track.path); // 配置为仅加载元数据,不拉取完整音频,节省流量 audio.preload = 'metadata'; audio.addEventListener('loadedmetadata', () => { const durationEl = document.querySelector(`[data-duration-role="${index}"]`); if (durationEl) { durationEl.textContent = formatDuration(audio.duration); } // 加载完成后释放音频实例占用的资源 audio.remove(); }); // 处理音频加载失败场景 audio.addEventListener('error', () => { const durationEl = document.querySelector(`[data-duration-role="${index}"]`); if (durationEl) { durationEl.textContent = "--:--"; } }); }); listStr += "</ul>"; playlist.innerHTML = listStr;
注意:如果音频资源和页面不同源,需要目标资源配置CORS允许跨域访问,否则无法读取元数据获取时长,本地同目录下的音频文件无此限制。
内容的提问来源于stack exchange,提问作者Avigo
相关产品推荐
相关产品推荐

