设置audio.currentTime后自动重置为0的技术求助
问题分析与解决方案
核心问题原因
- 重复绑定
loadedmetadata事件:每次调用loadSong都会新增一个loadedmetadata监听,多次触发时逻辑冲突,导致设置被干扰。 - 事件覆盖问题:代码同时用
addEventListener('loadedmetadata')和audio.onloadedmetadata = function(),后者会直接覆盖前者的绑定,部分逻辑失效。 - 媒体未进入可跳转状态:
loadedmetadata仅代表元数据加载完成,但媒体可能未缓存足够字节支持跳转,此时设置currentTime大概率会被重置。
修复后的代码
audio = document.querySelector('.audio'); let songIndex; // 单独定义元数据加载处理函数,方便移除重复监听 function handleMetadataLoaded() { console.log('audio.duration: ' + audio.duration); if (audio.duration >= 30) { // 等待媒体可播放后再设置跳转位置 audio.addEventListener('canplay', function setSeekPosition() { audio.currentTime = 30; console.log('CurrentTime: ' + audio.currentTime); // 仅执行一次,避免重复触发 audio.removeEventListener('canplay', setSeekPosition); }, { once: true }); } else { console.log('duration < 30'); } // 同步更新时长显示 songDuration.innerHTML = timeCalc(audio.duration); } // 初始化歌曲 fetch(music_default_url) .then(response => response.json()) .then(data => { dataLength = data.length; songIndex = Math.floor(Math.random() * dataLength); loadSong(data[songIndex]); console.log('DATA DOWNLOADED'); }) .catch(err => console.log(err)); // 加载歌曲逻辑 function loadSong(track) { title.innerHTML = track.data.title; artist.innerHTML = track.data.artist; // 先移除旧的监听,避免重复绑定 audio.removeEventListener('loadedmetadata', handleMetadataLoaded); audio.src = "/" + track.data.path.replace(/\\/g, "/"); // 绑定元数据加载事件,仅执行一次 audio.addEventListener('loadedmetadata', handleMetadataLoaded, { once: true }); // 实时更新当前时间显示 audio.addEventListener('timeupdate', function() { currentTimeBlock.innerHTML = timeCalc(audio.currentTime); }); let previewPath = "/" + track.data.coverImage.replace(/\\/g, "/"); previewImg.style.background = `url("${previewPath}")`; }
关键修复点
- 统一事件管理:用命名函数配合
removeEventListener避免重复绑定事件,防止逻辑冲突。 - 等待可播放状态:通过
canplay事件确认媒体缓存足够数据后再设置currentTime,确保跳转生效。 - 实时更新当前时间:原代码直接赋值时
audio.currentTime还未加载完成,改为监听timeupdate事件实时同步。 - 单次事件触发:使用
{ once: true }选项让事件仅执行一次,避免冗余逻辑。
内容的提问来源于stack exchange,提问作者Mihail Karetnik
相关产品推荐
相关产品推荐

