1396 字
7 分鐘
🎵 灰產進行曲丨音樂開發紀錄
2025-07-29
正在播放 灰產進行曲

背景音樂功能開發記錄#

📋 功能概述#

為 Astro 靜態網站實現了完整的背景音樂功能,包括:

  • ✅ 自動播放背景音樂
  • ✅ 圖標式播放/暫停控制
  • ✅ 音量控制
  • ✅ 循環播放設置
  • ✅ 音樂狀態顯示
  • ✅ 檔名顯示

🎯 開發過程記錄#

1. 初始問題與解決#

圖片 問題:MP3 文件無法播放

// 低級問題
原始代碼:src="./灰產進行曲.mp3"
問題:相對路徑無法正確解析

解決方案

1. 將 MP3 文件移動到 public/ 目錄
2. 修改路徑為絕對路徑:src="/灰產進行曲.mp3"
3. 在 frontmatter 中設置:audio: "/灰產進行曲.mp3"

2. 架構設計演進#

圖片

第一階段:內聯音頻標籤#

<audio src="/灰產進行曲.mp3" controls autoplay loop></audio>

第二階段:獨立組件#

src/components/misc/BackgroundAudio.astro
<audio id="background-audio" preload="auto" autoplay loop>
<source src={audio} type="audio/mpeg">
</audio>

第三階段:整合到 PostMeta 組件#

src/components/PostMeta.astro
{audio && (
<div class="flex items-center">
<div class="meta-icon">
<button id="play-pause-btn">
<Icon id="play-icon" name="material-symbols:play-arrow-rounded" />
<Icon id="pause-icon" name="material-symbols:pause-rounded" />
</button>
</div>
<div class="flex flex-row flex-nowrap items-center">
<span id="music-status">
<span id="status-text">正在播放</span>
<span id="music-filename">{audio.split('/').pop()?.replace('.mp3', '')}</span>
</span>
</div>
</div>
)}

3. 核心技術實現#

圖片

3.1 內容集合配置 (src/content/config.ts)#

const postsCollection = defineCollection({
schema: z.object({
// ... 其他字段
audio: z.string().optional().default(""), // 背景音樂文件路徑
audioLoop: z.boolean().optional().default(true), // 是否循環播放
audioVolume: z.number().optional().default(20), // 音量大小 (0-100,0為靜音,100為最大音量)
}),
});

3.2 組件 Props 接口 (src/components/PostMeta.astro)#

interface Props {
// ... 其他屬性
audio?: string;
audioLoop?: boolean;
audioVolume?: number;
}

3.3 JavaScript 控制邏輯#

function initAudioControls() {
const audio = document.getElementById('background-audio');
const playPauseBtn = document.getElementById('play-pause-btn');
const playIcon = document.getElementById('play-icon');
const pauseIcon = document.getElementById('pause-icon');
const statusText = document.getElementById('status-text');
// 設置音量 (0-100 轉換為 0.0-1.0)
const volumeData = document.querySelector('[data-audio-volume]');
const volumePercent = volumeData ? parseFloat(volumeData.getAttribute('data-audio-volume')) : 20;
audio.volume = volumePercent / 100;
// 自動播放
audio.play().then(() => {
console.log('音樂自動播放成功');
}).catch((e) => {
console.log('自動播放被阻止:', e);
});
// 播放/暫停控制
playPauseBtn.addEventListener('click', () => {
if (audio.paused) {
audio.play().catch((e) => console.log('播放失敗:', e));
} else {
audio.pause();
}
});
// 狀態更新
audio.addEventListener('play', () => {
playIcon.classList.add('hidden');
pauseIcon.classList.remove('hidden');
statusText.textContent = '正在播放';
});
audio.addEventListener('pause', () => {
playIcon.classList.remove('hidden');
pauseIcon.classList.add('hidden');
statusText.textContent = '已暫停';
});
}

4. 遇到的問題與解決#

圖片

4.1 瀏覽器自動播放限制#

問題:現代瀏覽器阻止未經用戶交互的自動播放 解決方案

// 使用 is:inline 腳本確保立即執行
<script is:inline>
(function() {
// 立即執行初始化
initAudioControls();
// 多重保險:DOMContentLoaded 和 window.load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initAudioControls);
}
window.addEventListener('load', initAudioControls);
})();
</script>

4.2 按鈕交互問題#

問題:首次進入頁面按鈕無法交互,需要刷新 解決方案

// 重試機制
if (!audio || !playPauseBtn || !playIcon || !pauseIcon || !statusText) {
setTimeout(initAudioControls, 50);
return;
}

4.3 音量控制實現#

需求:讓用戶可以在 frontmatter 中設置音量 實現

# 在文章 frontmatter 中
audioVolume: 20 # 音量大小 (0-100,0為靜音,100為最大音量)

音量範圍調整

  • 原始設計:0.0-1.0(HTML5 Audio API 標準)
  • 用戶需求:0-100(更直觀的百分比)
  • 實現方案:在 JavaScript 中將百分比轉換為 0.0-1.0
// 音量轉換邏輯
const volumePercent = volumeData ? parseFloat(volumeData.getAttribute('data-audio-volume')) : 20;
audio.volume = volumePercent / 100; // 將百分比轉換為 0.0-1.0

4.4 音量調整優化#

問題:默認音量過大,可能嚇到讀者 解決方案

  1. 調整默認音量:從 30% 降低到 20%
  2. 使用百分比範圍:0-100 比 0.0-1.0 更直觀
  3. 用戶體驗考慮:避免突然的大音量播放

修改文件

  • src/content/config.ts:默認音量從 0.3 改為 20
  • src/components/PostMeta.astro:添加百分比轉換邏輯

5. 最終功能特性#

圖片

5.1 Frontmatter 配置#

---
title: 文章標題
audio: "/音樂文件.mp3" # 音樂文件路徑(相對於 public 目錄)
audioLoop: true # 是否循環播放
audioVolume: 20 # 音量大小 (0-100,0為靜音,100為最大音量)
---

5.2 用戶界面#

  • 🎵 音樂圖標:點擊切換播放/暫停
  • 📊 狀態顯示:顯示當前播放狀態和檔名
  • 🎚️ 音量控制:通過 frontmatter 設置
  • 🔄 循環播放:可配置是否循環

5.3 響應式設計#

  • 與現有的分類、標籤設計保持一致
  • 只在有音樂設置的文章中顯示
  • 適配深色/淺色主題

🛠️ 技術棧#

  • 框架:Astro 5.11.0
  • 語言:TypeScript + JavaScript
  • 圖標:Material Symbols
  • 樣式:Tailwind CSS
  • 音頻:HTML5 Audio API

📁 修改的文件#

  1. src/content/config.ts - 添加音頻相關 schema
  2. src/pages/posts/[…slug].astro - 傳遞音頻參數
  3. src/components/PostMeta.astro - 實現音頻控制組件
  4. src/content/posts/生活向/灰產進行曲.md - 測試文章配置

🎉 開發成果#

功能完整性#

  • ✅ 自動播放背景音樂
  • ✅ 圖標式播放控制
  • ✅ 音量可配置
  • ✅ 循環播放可配置
  • ✅ 狀態顯示
  • ✅ 檔名顯示

開發體驗#

  • ✅ 配置簡單(只需 frontmatter)
  • ✅ 代碼可維護
  • ✅ 錯誤處理完善
  • ✅ 瀏覽器兼容性好
  • ✅ 我是真的很強,AI整理文本的能力也很強

🔮 未來擴展可能#

  1. 播放列表:支持多首音樂輪播(短期不用想了)
  2. 進度條:顯示播放進度(合理但不知道放哪)
  3. 音量滑塊:實時音量調整
  4. 播放模式:隨機播放、單曲循環等
  5. 音頻可視化:頻譜顯示(炫技)

📝 開發心得#

這次開發過程展示了如何:

  1. 逐步迭代:從簡單的 audio 標籤到完整的控制組件
  2. 解決瀏覽器限制:處理自動播放政策
  3. 保持代碼整潔:使用 TypeScript 類型定義
  4. 注重用戶體驗:即時響應和狀態反饋
  5. 文檔記錄:請AI詳細記錄開發過程供後人(徒弟)參考 圖片

開發日期:2025年7月29日
開發者:Illumi糖糖 + 本地部屬AI(Ollama)
技術棧:Astro + TypeScript + Tailwind CSS

🎵 灰產進行曲丨音樂開發紀錄
https://illumi.love/posts/指南向/灰產進行曲丨音樂開發紀錄/
作者
Illumi糖糖
發布於
2025-07-29
許可協議
🔒CC BY-NC-ND 4.0