博客音乐播放器实现全解析

博客音乐播放器实现详解

本文从零到一介绍博客中音乐播放器的搭建过程、技术原理、数据来源,以及如何切换歌单。


一、效果概览

博客底部固定显示一个迷你音乐播放器,支持:

  • 播放/暂停/切歌
  • 歌词滚动显示
  • 播放列表展示
  • 随机/顺序/单曲循环
  • 音量调节
  • 自动记住播放设置

二、技术选型

技术 作用
APlayer 开源 HTML5 音乐播放器,提供 UI 和播放控制
Meting API 第三方音乐聚合 API,支持网易云、QQ 音乐等
Vue 3 组件 封装 APlayer 为 Vue 组件
Pinia 状态管理,存储网站配置(含歌单 ID)

为什么选 APlayer?

APlayer 是目前最流行的前端音乐播放器库,具有:

  • 开箱即用的精美 UI
  • 支持歌词(LRC 格式)
  • 吸底/迷你模式
  • 完善的 API 和事件系统
  • 体积小(~12KB gzipped)

三、组件架构

复制代码
App.vue
  └── <MusicPlayer>               (总入口)
        └── <aplayer>              (APlayer 实例封装)
              ├── 获取歌单数据     (从 Meting API)
              └── 创建 APlayer     (渲染播放器)

3.1 入口组件 MusicPlayer/index.vue

vue 复制代码
<template>
  <aplayer
    server="netease"
    type="playlist"
    :id="blog.blogInfoSafe.siteConfig.musicId"
    :fixed="true"
    theme="#e9546b"
  />
</template>

<script setup lang="ts">
import { useBlogStore } from "@/store";
import aplayer from "./aplayer.vue";
const blog = useBlogStore();
</script>

关键点说明:

属性 含义
server "netease" 音乐来源为网易云音乐
type "playlist" 类型为播放列表(歌单)
:id musicId 歌单 ID,从后台配置读取
:fixed true 吸底固定模式
theme "#e9546b" 播放器主题色(粉红色)

3.2 APlayer 封装组件 MusicPlayer/aplayer.vue

这是核心组件,完成三件事:

  1. 定义 Props:接收播放器配置参数
  2. 请求歌单数据:调用 Meting API 获取歌曲列表
  3. 创建 APlayer 实例:传入容器和配置,渲染播放器
vue 复制代码
<template>
  <div ref="playerRef"></div>
</template>

<script setup lang="ts">
import APlayer from "aplayer";
import "aplayer/dist/APlayer.min.css";

// APlayer 歌曲信息结构
class Audio {
  author: String;   // 歌手
  title: String;    // 歌名
  url: String;      // 音频链接
  pic: String;      // 封面图
  lrc: String;      // 歌词

  constructor(artist, name, url, cover, lrc) {
    this.author = artist;
    this.title = name;
    this.url = url;
    this.pic = cover;
    this.lrc = lrc;
  }
}

// 组件挂载后,请求歌单并创建播放器
onMounted(() => {
  nextTick(() => {
    request({
      url: `https://api.i-meto.com/meting/api?server=${props.server}&type=${props.type}&id=${props.id}&r=${Math.random()}`,
      method: "get",
    }).then(({ data }) => {
      instance = new APlayer({
        container: playerRef.value,
        fixed: props.fixed,
        mini: props.mini,
        autoplay: props.autoplay,
        theme: props.theme,
        loop: props.loop,
        order: props.order,
        preload: props.preload,
        volume: props.volume,
        mutex: props.mutex,
        lrcType: props.lrcType,
        listFolded: props.listFolded,
        listMaxHeight: props.listMaxHeight,
        storageName: props.storageName,
        audio: data,  // 歌曲数组
      });
    });
  });
});

// 组件销毁时清理
onBeforeUnmount(() => {
  instance.destroy();
});
</script>

Props 完整列表:

Prop 类型 默认值 说明
fixed Boolean true 吸底模式
mini Boolean true 迷你模式
autoplay Boolean false 自动播放
theme String rgba(255,255,255,0.2) 主题色
loop String "all" 循环模式(all/one/none)
order String "random" 播放顺序(list/random)
preload String "auto" 预加载策略
volume Number 0.7 默认音量
server String "netease" 音乐平台
type String "playlist" 播放类型
id String "186016" 歌单 ID
mutex Boolean true 互斥播放
lrcType Number 3 歌词类型(3=LRC 文本)
listFolded Boolean true 列表默认折叠
listMaxHeight String "100px" 列表最大高度
storageName String "aplayer-setting" 本地存储 key

四、数据来源

4.1 歌单 ID 从哪来?

歌单 ID 存储在后台数据库t_site_config 表中:

sql 复制代码
-- 数据库字段
is_music    INT     -- 是否开启播放器(0否 1是)
music_id    VARCHAR -- 网易云歌单 ID

对应 Java 实体:

java 复制代码
// SiteConfig.java
@TableField("is_music")
private Integer isMusic;

@TableField("music_id")
private String musicId;

数据流向:

复制代码
管理后台配置 musicId
  → PUT /admin/site/update (更新数据库 + 清除 Redis)
  → 用户访问博客 → GET / (获取 blogInfo)
  → 前端 Pinia store 存储 siteConfig.musicId
  → MusicPlayer 组件读取 musicId
  → 拼接 Meting API URL 请求歌单

4.2 Meting API 是什么?

Meting API 是一个免费的音乐聚合接口,支持多个平台:

server 值 平台
netease 网易云音乐
tencent QQ 音乐
kugou 酷狗音乐
xiami 虾米音乐
baidu 百度音乐

请求格式:

复制代码
GET https://api.i-meto.com/meting/api?server=netease&type=playlist&id=歌单ID&r=随机数

返回格式(JSON 数组):

json 复制代码
[
  {
    "name": "歌名",
    "artist": "歌手",
    "url": "https://music.163.com/song/media/outer/url?id=xxx.mp3",
    "cover": "https://p1.music.126.net/xxx.jpg",
    "lrc": "[00:00.000] 歌词内容..."
  },
  // ...更多歌曲
]

4.3 如何获取网易云歌单 ID?

  1. 打开 网易云音乐
  2. 找到你喜欢的歌单
  3. 歌单页面 URL 形如:https://music.163.com/#/playlist?id=186016
  4. 其中 186016 就是歌单 ID

五、如何切换歌单

方法一:后台管理切换(推荐)

  1. 登录管理后台
  2. 进入 网站管理网站配置其他设置
  3. 找到「网易云歌单 ID」输入框
  4. 填入新的歌单 ID
  5. 保存

原理PUT /admin/site/update 更新数据库,同时删除 Redis 缓存。用户刷新页面后,GET / 返回最新配置,播放器自动加载新歌单。

方法二:前端代码切换音乐平台

如果想换成 QQ 音乐歌单,修改 MusicPlayer/index.vue

vue 复制代码
<aplayer
  server="tencent"           <!-- 改为 tencent -->
  type="playlist"
  :id="blog.blogInfoSafe.siteConfig.musicId"   <!-- ID 改为 QQ 音乐歌单 ID -->
  :fixed="true"
  theme="#e9546b"
/>

目前的限制

  • 歌单切换需要刷新页面才能生效(APlayer 实例只在 onMounted 时创建一次)
  • 不支持前端动态切换多个歌单
  • server 平台类型硬编码在 index.vue 中,无法从后台配置

如果想支持动态切换?

可以把 server 也加入 SiteConfig,然后前端 watch musicId 变化时销毁旧实例、创建新实例:

typescript 复制代码
watch(() => props.id, () => {
  if (instance) instance.destroy();
  // 重新请求并创建
});

六、播放器样式定制

全局样式 common.scss

scss 复制代码
/* 吸底模式下迷你播放器的宽度调整 */
.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
  left: -66px !important;
}
.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
  left: 0 !important;
}

这段 CSS 让播放器在迷你模式下默认隐藏部分内容,鼠标悬停时完整展示。


七、整体数据流图

复制代码
┌─────────────────────────────────────────────────────────┐
│               管理后台 (shoka-admin)                     │
│   网站配置 → musicId: "186016"                           │
│   → PUT /admin/site/update                               │
└─────────────┬───────────────────────────────────────────┘
              │ 更新 DB + 清除 Redis
              ▼
┌─────────────────────────────────────────────────────────┐
│               Spring Boot 后端                           │
│   SiteConfig { isMusic: 1, musicId: "186016" }          │
│   GET / → BlogInfoResp { siteConfig: { ... } }          │
└─────────────┬───────────────────────────────────────────┘
              │ 返回 JSON
              ▼
┌─────────────────────────────────────────────────────────┐
│               Vue 前端 (shoka-blog)                      │
│   Pinia Store → blog.siteConfig.musicId = "186016"      │
│                                                          │
│   MusicPlayer/index.vue                                  │
│     └── <aplayer id="186016" server="netease" ...>       │
│                                                          │
│   MusicPlayer/aplayer.vue                                │
│     └── fetch Meting API → [歌曲数组]                    │
│     └── new APlayer({ audio: [歌曲数组], ... })          │
│     └── 🎵 播放器渲染完成!                               │
└─────────────────────────────────────────────────────────┘
              │ HTTP GET
              ▼
┌─────────────────────────────────────────────────────────┐
│           Meting API (第三方服务)                         │
│   https://api.i-meto.com/meting/api                      │
│   ?server=netease&type=playlist&id=186016                │
│   返回: [{ name, artist, url, cover, lrc }, ...]         │
└─────────────────────────────────────────────────────────┘

八、常见问题

Q1: 播放器不显示?

  • 检查后台 isMusic 是否开启(当前代码未使用此字段判断,播放器始终显示)
  • 检查 Meting API 是否可访问:https://api.i-meto.com/meting/api?server=netease&type=playlist&id=186016
  • 检查浏览器控制台是否有 CORS 错误

Q2: 歌曲无法播放?

  • 网易云部分歌曲有版权限制,Meting API 无法获取播放链接
  • 尝试换一个包含更多无版权歌曲的歌单

Q3: 本地开发报错 Two output files share the same path

  • 原因:global.d.tsdeclare module "APlayer" 大写,实际导入用小写 "aplayer"
  • 解决:统一改为 declare module "aplayer",然后删除 node_modules/.vite 缓存

Q4: 想关闭播放器?

  • 虽然后台有 isMusic 开关,但当前代码未使用此字段
  • 如需启用,在 index.vue 添加 v-if="blog.blogInfoSafe.siteConfig.isMusic"

九、涉及的文件清单

文件路径 作用
shoka-blog/src/components/MusicPlayer/index.vue 播放器入口组件
shoka-blog/src/components/MusicPlayer/aplayer.vue APlayer 实例封装
shoka-blog/src/assets/styles/common.scss 播放器样式覆盖
shoka-blog/src/types/global.d.ts APlayer 模块声明
blog-springboot/.../entity/SiteConfig.java 数据库实体(musicId)
blog-springboot/.../service/BlogInfoService.java 返回博客配置信息
blog-springboot/.../service/SiteConfigService.java 站点配置 CRUD + Redis

十、总结

博客的音乐播放器由以下几个关键环节组成:

  1. 后台配置:管理员在网站配置中设置网易云歌单 ID
  2. 数据存储:歌单 ID 存在 MySQL + Redis 缓存
  3. 前端获取 :页面加载时通过 GET / 获取配置
  4. 歌曲请求:通过 Meting API 将歌单 ID 转换为实际歌曲列表
  5. 播放器渲染:APlayer 接收歌曲数据,渲染吸底播放器

整个流程简洁高效,核心代码不到 200 行。如需扩展(如支持多歌单切换、多平台选择),只需在 SiteConfig 中增加相应字段并在前端 watch 变化即可。

相关推荐
sanyii3131312 小时前
k8s核心资源Pod-主容器之钩子函数
云原生·容器·kubernetes
Mintopia2 小时前
Python被广泛认为是数据预警和数据处理的首选语言
人工智能
Mintopia2 小时前
如何搭建AI数据预警服务
人工智能
骥龙2 小时前
第八篇:成效篇 - 数字说话:平台上线一年的ROI分析
大数据·人工智能·机器学习
静谧空间2 小时前
linux安装Squid
linux·运维·爬虫
2501_941982052 小时前
Python开发:实现企微外部群消息关键词监控
java·服务器·数据库
玖&司2 小时前
机器学习中的多层感知机(MLP)
人工智能·机器学习
Songbl_2 小时前
机器学习特征工程
人工智能·机器学习