Search K
Appearance
Appearance
关键词: HTML5音频元素, audio标签, 音频格式, 音频播放, 音频控制, 音频事件, 音频API, 多媒体, 音频兼容性
<audio controls>
<source src="audio.mp3" type="audio/mpeg">
<source src="audio.ogg" type="audio/ogg">
您的浏览器不支持音频播放
</audio>HTML5的audio元素提供了在网页中嵌入音频内容的标准方法,支持多种音频格式。
<audio
controls <!-- 显示播放控件 -->
autoplay <!-- 自动播放 -->
loop <!-- 循环播放 -->
muted <!-- 静音 -->
preload="auto" <!-- 预加载策略 -->
volume="0.5" <!-- 音量(0-1) -->
src="audio.mp3"> <!-- 音频源 -->
</audio><!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>音频元素示例</title>
<style>
.audio-container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.audio-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 6px;
background-color: #f8f9fa;
}
.audio-section h4 {
margin-top: 0;
color: #495057;
}
.custom-audio-player {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
border-radius: 10px;
color: white;
margin: 15px 0;
}
.player-controls {
display: flex;
align-items: center;
gap: 15px;
margin-top: 15px;
}
.control-btn {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background-color: rgba(255,255,255,0.2);
color: white;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
transition: background-color 0.3s;
}
.control-btn:hover {
background-color: rgba(255,255,255,0.3);
}
.progress-container {
flex: 1;
height: 6px;
background-color: rgba(255,255,255,0.3);
border-radius: 3px;
cursor: pointer;
position: relative;
}
.progress-bar {
height: 100%;
background-color: white;
border-radius: 3px;
width: 0%;
transition: width 0.1s;
}
.time-display {
font-size: 14px;
font-family: monospace;
}
.volume-control {
display: flex;
align-items: center;
gap: 10px;
}
.volume-slider {
width: 80px;
}
.playlist {
background-color: white;
border-radius: 8px;
padding: 15px;
margin-top: 20px;
}
.playlist-item {
display: flex;
align-items: center;
padding: 10px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.playlist-item:hover {
background-color: #f8f9fa;
}
.playlist-item.active {
background-color: #007bff;
color: white;
}
.waveform {
height: 60px;
background: linear-gradient(90deg, #ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #ffeaa7);
border-radius: 4px;
margin: 10px 0;
position: relative;
overflow: hidden;
}
.waveform::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: repeating-linear-gradient(
90deg,
transparent,
transparent 2px,
rgba(255,255,255,0.3) 2px,
rgba(255,255,255,0.3) 4px
);
}
.audio-info {
background-color: #e3f2fd;
padding: 15px;
border-radius: 4px;
margin: 15px 0;
}
.audio-info h5 {
margin: 0 0 10px 0;
color: #1976d2;
}
.info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
}
.info-item {
display: flex;
justify-content: space-between;
padding: 5px 0;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<div class="audio-container">
<h3>HTML5音频元素示例</h3>
<div class="audio-section">
<h4>基础音频播放器</h4>
<audio controls style="width: 100%;">
<source src="data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgodDbq2EcBj+a2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmwhBToAAAAAAACAhYqFbF1fdJivrJBhNjVgodDbq2EcBj+a2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmwhBTqa2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmwhBQAAAAAAAAA" type="audio/wav">
您的浏览器不支持音频播放
</audio>
<p style="font-size: 12px; color: #666; margin-top: 10px;">
基础的HTML5音频播放器,带有浏览器默认控件
</p>
</div>
<div class="audio-section">
<h4>自定义音频播放器</h4>
<div class="custom-audio-player">
<div style="text-align: center;">
<h5 style="margin: 0 0 5px 0;">🎵 示例音频</h5>
<p style="margin: 0; opacity: 0.8; font-size: 14px;">HTML5音频演示</p>
</div>
<div class="waveform" id="waveform"></div>
<div class="player-controls">
<button class="control-btn" id="playPauseBtn" onclick="togglePlayPause()">
<span id="playIcon">▶️</span>
</button>
<button class="control-btn" onclick="stopAudio()">⏹️</button>
<div class="progress-container" onclick="seekAudio(event)">
<div class="progress-bar" id="progressBar"></div>
</div>
<div class="time-display">
<span id="currentTime">0:00</span> / <span id="duration">0:00</span>
</div>
<div class="volume-control">
<span>🔊</span>
<input type="range" class="volume-slider" id="volumeSlider"
min="0" max="1" step="0.1" value="0.5" onchange="changeVolume()">
</div>
</div>
</div>
<audio id="customAudio" preload="auto">
<source src="data:audio/wav;base64,UklGRnoGAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoGAACBhYqFbF1fdJivrJBhNjVgodDbq2EcBj+a2/LDciUFLIHO8tiJNwgZaLvt559NEAxQp+PwtmMcBjiR1/LMeSwFJHfH8N2QQAoUXrTp66hVFApGn+DyvmwhBQAAAAA" type="audio/wav">
</audio>
</div>
<div class="audio-section">
<h4>音频信息显示</h4>
<div class="audio-info">
<h5>当前音频信息</h5>
<div class="info-grid">
<div class="info-item">
<span>持续时间:</span>
<span id="infoDuration">未知</span>
</div>
<div class="info-item">
<span>当前时间:</span>
<span id="infoCurrentTime">0:00</span>
</div>
<div class="info-item">
<span>音量:</span>
<span id="infoVolume">50%</span>
</div>
<div class="info-item">
<span>播放状态:</span>
<span id="infoStatus">暂停</span>
</div>
<div class="info-item">
<span>缓冲进度:</span>
<span id="infoBuffered">0%</span>
</div>
<div class="info-item">
<span>播放速度:</span>
<span id="infoPlaybackRate">1.0x</span>
</div>
</div>
</div>
</div>
<div class="audio-section">
<h4>播放控制选项</h4>
<div style="display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 15px;">
<button onclick="changePlaybackRate(0.5)" style="padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; cursor: pointer;">
0.5x 慢速
</button>
<button onclick="changePlaybackRate(1.0)" style="padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; cursor: pointer;">
1.0x 正常
</button>
<button onclick="changePlaybackRate(1.5)" style="padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; cursor: pointer;">
1.5x 快速
</button>
<button onclick="changePlaybackRate(2.0)" style="padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; cursor: pointer;">
2.0x 超快
</button>
</div>
<div style="margin-bottom: 15px;">
<label style="display: block; margin-bottom: 5px; font-weight: bold;">跳转到指定时间:</label>
<input type="range" id="seekSlider" min="0" max="100" value="0"
style="width: 100%;" onchange="seekToTime()">
</div>
</div>
<div class="audio-section">
<h4>音频事件日志</h4>
<div id="eventLog" style="background-color: #f8f9fa; padding: 15px; border-radius: 4px; height: 150px; overflow-y: scroll; font-family: monospace; font-size: 12px;">
<div style="color: #666;">音频事件将在这里显示...</div>
</div>
<button onclick="clearEventLog()" style="margin-top: 10px; padding: 8px 15px; background-color: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer;">
清除日志
</button>
</div>
</div>
<script>
const audio = document.getElementById('customAudio');
const playPauseBtn = document.getElementById('playPauseBtn');
const playIcon = document.getElementById('playIcon');
const progressBar = document.getElementById('progressBar');
const currentTimeSpan = document.getElementById('currentTime');
const durationSpan = document.getElementById('duration');
const volumeSlider = document.getElementById('volumeSlider');
const eventLog = document.getElementById('eventLog');
// 音频事件监听
const audioEvents = [
'loadstart', 'loadeddata', 'loadedmetadata', 'canplay', 'canplaythrough',
'play', 'pause', 'ended', 'timeupdate', 'progress', 'volumechange',
'durationchange', 'ratechange', 'seeking', 'seeked'
];
audioEvents.forEach(eventType => {
audio.addEventListener(eventType, function(e) {
logEvent(eventType, this);
});
});
function logEvent(eventType, audioElement) {
const timestamp = new Date().toLocaleTimeString();
const logEntry = document.createElement('div');
logEntry.style.color = getEventColor(eventType);
let message = `[${timestamp}] ${eventType}`;
switch(eventType) {
case 'timeupdate':
message += ` - 当前时间: ${formatTime(audioElement.currentTime)}`;
break;
case 'progress':
const buffered = audioElement.buffered;
if (buffered.length > 0) {
const bufferedEnd = buffered.end(buffered.length - 1);
const duration = audioElement.duration || 0;
const percent = duration > 0 ? (bufferedEnd / duration * 100).toFixed(1) : 0;
message += ` - 缓冲: ${percent}%`;
document.getElementById('infoBuffered').textContent = `${percent}%`;
}
break;
case 'volumechange':
message += ` - 音量: ${(audioElement.volume * 100).toFixed(0)}%`;
break;
case 'ratechange':
message += ` - 播放速度: ${audioElement.playbackRate}x`;
break;
}
logEntry.textContent = message;
eventLog.appendChild(logEntry);
eventLog.scrollTop = eventLog.scrollHeight;
}
function getEventColor(eventType) {
const colors = {
'loadstart': '#007bff',
'loadeddata': '#28a745',
'loadedmetadata': '#17a2b8',
'canplay': '#28a745',
'canplaythrough': '#28a745',
'play': '#28a745',
'pause': '#ffc107',
'ended': '#dc3545',
'timeupdate': '#6c757d',
'progress': '#17a2b8',
'volumechange': '#6f42c1',
'ratechange': '#fd7e14',
'seeking': '#20c997',
'seeked': '#20c997'
};
return colors[eventType] || '#333';
}
function togglePlayPause() {
if (audio.paused) {
audio.play();
playIcon.textContent = '⏸️';
document.getElementById('infoStatus').textContent = '播放中';
} else {
audio.pause();
playIcon.textContent = '▶️';
document.getElementById('infoStatus').textContent = '暂停';
}
}
function stopAudio() {
audio.pause();
audio.currentTime = 0;
playIcon.textContent = '▶️';
document.getElementById('infoStatus').textContent = '停止';
}
function seekAudio(event) {
const progressContainer = event.currentTarget;
const clickX = event.offsetX;
const width = progressContainer.offsetWidth;
const duration = audio.duration;
if (duration) {
const newTime = (clickX / width) * duration;
audio.currentTime = newTime;
}
}
function changeVolume() {
audio.volume = volumeSlider.value;
document.getElementById('infoVolume').textContent = `${Math.round(audio.volume * 100)}%`;
}
function changePlaybackRate(rate) {
audio.playbackRate = rate;
document.getElementById('infoPlaybackRate').textContent = `${rate}x`;
}
function seekToTime() {
const seekSlider = document.getElementById('seekSlider');
const duration = audio.duration;
if (duration) {
const newTime = (seekSlider.value / 100) * duration;
audio.currentTime = newTime;
}
}
function formatTime(seconds) {
if (isNaN(seconds)) return '0:00';
const minutes = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${minutes}:${secs.toString().padStart(2, '0')}`;
}
function clearEventLog() {
eventLog.innerHTML = '<div style="color: #666;">音频事件将在这里显示...</div>';
}
// 实时更新进度条和时间显示
audio.addEventListener('timeupdate', function() {
const duration = this.duration;
const currentTime = this.currentTime;
if (duration) {
const progress = (currentTime / duration) * 100;
progressBar.style.width = `${progress}%`;
// 更新滑块位置
document.getElementById('seekSlider').value = progress;
}
currentTimeSpan.textContent = formatTime(currentTime);
document.getElementById('infoCurrentTime').textContent = formatTime(currentTime);
});
// 音频加载完成后更新持续时间
audio.addEventListener('loadedmetadata', function() {
durationSpan.textContent = formatTime(this.duration);
document.getElementById('infoDuration').textContent = formatTime(this.duration);
document.getElementById('seekSlider').max = this.duration;
});
// 音频结束时重置播放按钮
audio.addEventListener('ended', function() {
playIcon.textContent = '▶️';
document.getElementById('infoStatus').textContent = '播放完成';
});
// 初始化音量
audio.volume = 0.5;
document.getElementById('infoVolume').textContent = '50%';
document.getElementById('infoPlaybackRate').textContent = '1.0x';
</script>
</body>
</html>| 格式 | 浏览器支持 | 文件大小 | 音质 | 适用场景 |
|---|---|---|---|---|
| MP3 | 极好 | 中等 | 好 | 通用音频 |
| OGG | 较好 | 小 | 很好 | 开源项目 |
| WAV | 好 | 大 | 极好 | 高质量音频 |
| AAC | 好 | 小 | 很好 | 移动设备 |
| FLAC | 有限 | 大 | 无损 | 专业音频 |
function checkAudioSupport() {
const audio = document.createElement('audio');
const formats = {
mp3: audio.canPlayType('audio/mpeg'),
ogg: audio.canPlayType('audio/ogg'),
wav: audio.canPlayType('audio/wav'),
aac: audio.canPlayType('audio/aac'),
flac: audio.canPlayType('audio/flac')
};
console.log('音频格式支持情况:', formats);
return formats;
}// 只读属性
audio.duration // 音频总时长
audio.currentTime // 当前播放时间
audio.paused // 是否暂停
audio.ended // 是否播放完成
audio.buffered // 缓冲范围
// 可设置属性
audio.volume // 音量 (0-1)
audio.playbackRate // 播放速度
audio.currentTime // 跳转到指定时间
audio.muted // 静音状态// 播放控制
audio.play() // 播放
audio.pause() // 暂停
audio.load() // 重新加载
// 检测支持
audio.canPlayType('audio/mpeg') // 检测格式支持audio.addEventListener('loadstart', function() {
console.log('开始加载音频');
});
audio.addEventListener('loadedmetadata', function() {
console.log('音频元数据加载完成');
console.log('时长:', this.duration);
});
audio.addEventListener('canplay', function() {
console.log('可以开始播放');
});audio.addEventListener('play', function() {
console.log('开始播放');
});
audio.addEventListener('pause', function() {
console.log('暂停播放');
});
audio.addEventListener('ended', function() {
console.log('播放结束');
});audio.addEventListener('timeupdate', function() {
console.log('播放进度更新:', this.currentTime);
});
audio.addEventListener('progress', function() {
console.log('缓冲进度更新');
});<audio controls>
<source src="audio.mp3" type="audio/mpeg">
<source src="audio.ogg" type="audio/ogg">
<source src="audio.wav" type="audio/wav">
<p>您的浏览器不支持HTML5音频。
<a href="audio.mp3">点击下载音频文件</a>
</p>
</audio>function playAudio(audioSrc) {
const audio = new Audio();
if (audio.canPlayType) {
// 支持HTML5音频
audio.src = audioSrc;
audio.play().catch(error => {
console.log('播放失败:', error);
// 降级到其他方案
fallbackAudioPlayer(audioSrc);
});
} else {
// 不支持HTML5音频
fallbackAudioPlayer(audioSrc);
}
}
function fallbackAudioPlayer(audioSrc) {
// 使用Flash播放器或提示下载
alert('您的浏览器不支持音频播放,请升级浏览器或下载音频文件');
}A: 现代浏览器为了用户体验,限制了自动播放功能。音频自动播放通常需要用户先与页面交互。
A: MP3兼容性最好,OGG文件更小,WAV质量最高。建议提供多种格式以确保兼容性。
A: 可以使用preload属性控制预加载策略,或者选择压缩率更高的音频格式。
A: 需要使用Web Audio API配合Canvas或WebGL来实现音频频谱可视化。
下一节预览:第4章第2节 - 视频元素 - 学习HTML5视频元素的使用