Files
home/audio-player.html
hehh 532cbafd8e feat(audio): 重构音频播放功能以支持iframe隔离播放
- 将音频播放器移至独立的iframe中以提升性能和隔离性
- 实现主页面与iframe之间的postMessage通信机制
- 添加音频播放状态同步和UI更新逻辑
- 支持自动播放控制和用户交互检测
- 实现播放状态持久化存储和恢复功能
- 优化移动端音频控制体验
- 添加版权信息更新和国际化支持
2025-11-30 16:42:00 +08:00

208 lines
8.1 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audio Player</title>
<style>
body {
margin: 0;
padding: 0;
background: transparent;
}
</style>
</head>
<body>
<audio id="audio-player" controls autoplay style="display: none;"></audio>
<script>
const audio = document.getElementById('audio-player');
let currentSrc = '';
let isStateBroadcasting = false;
// 监听来自主页面的消息
window.addEventListener('message', function(event) {
// 允许来自同域的所有窗口的消息
if (event.origin !== window.location.origin) return;
const data = event.data;
switch (data.action) {
case 'play':
// 如果当前正在播放,则暂停;否则播放
if (audio.paused) {
audio.play().catch(e => console.error('播放失败:', e));
} else {
audio.pause();
}
// 发送状态更新回所有可能的窗口
broadcastState();
break;
case 'pause':
if (!audio.paused) {
audio.pause();
}
broadcastState();
break;
case 'setTrack':
if (currentSrc !== data.src) {
currentSrc = data.src;
audio.src = data.src;
audio.load();
// 自动播放新曲目
setTimeout(() => {
audio.play().catch(e => console.error('播放失败:', e));
broadcastState();
}, 100);
}
break;
case 'setVolume':
audio.volume = data.volume;
broadcastState();
break;
case 'getCurrentState':
// 向请求方发送当前状态
event.source.postMessage({
action: 'currentState',
playing: !audio.paused,
src: audio.src,
volume: audio.volume,
currentTime: audio.currentTime,
duration: audio.duration || 0
}, event.origin);
break;
}
});
// 广播状态到所有可能监听的窗口
function broadcastState() {
if (isStateBroadcasting) return; // 防止状态广播循环
isStateBroadcasting = true;
window.parent.postMessage({
action: 'stateChange',
playing: !audio.paused,
src: audio.src,
volume: audio.volume,
currentTime: audio.currentTime,
duration: audio.duration || 0
}, '*');
// 保存播放状态
savePlaybackState();
setTimeout(() => {
isStateBroadcasting = false;
}, 10);
}
// 监听音频事件并通知主页面
audio.addEventListener('play', function() {
broadcastState();
});
audio.addEventListener('pause', function() {
broadcastState();
});
audio.addEventListener('ended', function() {
window.parent.postMessage({
action: 'trackEnded'
}, '*');
});
// 页面加载完成后通知主页面
window.addEventListener('load', function() {
// 恢复之前保存的播放状态
restorePlaybackState();
window.parent.postMessage({
action: 'playerReady'
}, '*');
});
// 页面可见性变化时处理
document.addEventListener('visibilitychange', function() {
if (!document.hidden) {
// 页面变为可见时,广播当前状态
setTimeout(broadcastState, 100);
}
});
// 页面即将卸载时保存播放状态
window.addEventListener('beforeunload', function() {
savePlaybackState();
});
// 保存播放状态到 sessionStorage
function savePlaybackState() {
try {
sessionStorage.setItem('audioState', JSON.stringify({
src: audio.src,
currentTime: audio.currentTime,
playing: !audio.paused,
volume: audio.volume,
timestamp: Date.now()
}));
} catch (e) {
console.error('保存音频状态失败:', e);
}
}
// 从 sessionStorage 恢复播放状态
function restorePlaybackState() {
try {
const savedState = sessionStorage.getItem('audioState');
if (savedState) {
const state = JSON.parse(savedState);
// 如果状态保存时间不超过1小时则恢复播放
if (Date.now() - state.timestamp < 3600000) {
currentSrc = state.src;
audio.src = state.src;
audio.volume = state.volume !== undefined ? state.volume : 1.0;
audio.currentTime = state.currentTime || 0;
// 确保在用户交互后才尝试播放
if (state.playing) {
// 检查是否已经有用户交互
if (document.hasFocus()) {
// 稍微延迟播放,确保一切准备就绪
setTimeout(() => {
audio.play().catch(e => {
console.error('恢复播放失败:', e);
// 如果自动播放失败,等待用户交互后再播放
const tryPlayOnInteraction = () => {
audio.play().catch(console.error);
document.removeEventListener('click', tryPlayOnInteraction);
document.removeEventListener('touchstart', tryPlayOnInteraction);
};
document.addEventListener('click', tryPlayOnInteraction, { once: true });
document.addEventListener('touchstart', tryPlayOnInteraction, { once: true });
});
}, 300);
} else {
// 等待用户交互后再播放
const tryPlayOnInteraction = () => {
audio.play().catch(console.error);
document.removeEventListener('click', tryPlayOnInteraction);
document.removeEventListener('touchstart', tryPlayOnInteraction);
};
document.addEventListener('click', tryPlayOnInteraction, { once: true });
document.addEventListener('touchstart', tryPlayOnInteraction, { once: true });
}
}
}
}
} catch (e) {
console.error('恢复音频状态失败:', e);
}
}
</script>
</body>
</html>