20260830图卦音频版
`; const audio = root.querySelector('audio'); const image = root.querySelector('.cover'); const button = root.querySelector('.play'); const restart = root.querySelector('.restart'); const backward = root.querySelector('.backward'); const forward = root.querySelector('.forward'); const rateButton = root.querySelector('.rate'); const rateMenu = root.querySelector('.rate-menu'); const range = root.querySelector('input'); const current = root.querySelector('.current'); const duration = root.querySelector('.duration'); const status = root.querySelector('.status'); root.querySelector('.title').textContent = title; audio.src = src; image.src = cover; image.addEventListener('error', () => { if (image.src !== defaultCover) image.src = defaultCover; }); const time = value => Number.isFinite(value) ? Math.floor(value / 60) + ':' + String(Math.floor(value % 60)).padStart(2, '0') : '--:--'; const sync = () => { button.textContent = audio.paused ? '▶' : '❚❚'; button.setAttribute('aria-label', audio.paused ? '播放' : '暂停'); current.textContent = time(audio.currentTime); duration.textContent = time(audio.duration); range.value = audio.duration ? String(Math.round(audio.currentTime / audio.duration * 1000)) : '0'; }; restart.addEventListener('click', () => { audio.currentTime = 0; sync(); }); backward.addEventListener('click', () => { audio.currentTime = Math.max(0, (audio.currentTime || 0) - 10); sync(); }); button.addEventListener('click', () => audio.paused ? audio.play().catch(() => status.textContent = '暂时无法播放,请稍后重试。') : audio.pause()); forward.addEventListener('click', () => { audio.currentTime = Math.min(audio.duration || Infinity, (audio.currentTime || 0) + 10); sync(); }); rateButton.addEventListener('click', event => { event.stopPropagation(); rateMenu.hidden = !rateMenu.hidden; rateButton.setAttribute('aria-expanded', String(!rateMenu.hidden)); }); rateMenu.addEventListener('click', event => { const option = event.target.closest('[data-rate]'); if (!option) return; const rate = Number(option.dataset.rate) || 1; audio.playbackRate = rate; rateButton.textContent = rate + 'x'; rateMenu.querySelectorAll('[data-rate]').forEach(item => item.classList.toggle('active', Number(item.dataset.rate) === rate)); rateMenu.hidden = true; rateButton.setAttribute('aria-expanded', 'false'); }); root.addEventListener('click', event => { if (!event.target.closest('.rate-wrap')) { rateMenu.hidden = true; rateButton.setAttribute('aria-expanded', 'false'); } }); range.addEventListener('input', () => { if (audio.duration) audio.currentTime = Number(range.value) / 1000 * audio.duration; }); ['loadedmetadata','timeupdate','play','pause','ended'].forEach(name => audio.addEventListener(name, sync)); audio.addEventListener('error', () => status.textContent = '音频加载失败,请检查网络后重试。'); } } customElements.define('dapenti-audio-card', DapentiAudioCard); })();

共有 0 条评论