
前言
Jasmine主题简约而又强大,配合Meting Aplayer 可以得到相当不错的体验,但是仅限于文章页面,我希望能在保留两者的强大功能的情况下,将播放器深度集成进网站,在查找源码询问ai以后一番折腾便有了如下教程,感谢ai
正文:在 Jasmine 主题首页集成 Meting APlayer 音乐播放器
前置说明
在实际部署中,三个项目的目录结构如下(并不在同一层级):
Typecho 根目录/
├── usr/
│ ├── plugins/
│ │ └── Meting/ ← Meting Aplayer 插件(重命名后放在这里)
│ │ ├── Plugin.php
│ │ ├── Action.php
│ │ ├── assets/
│ │ ├── driver/
│ │ └── include/
│ └── themes/
│ └── Jasmine/ ← Jasmine 主题
│ ├── index.php
│ ├── template-parts/
│ │ ├── header.php
│ │ ├── footer.php
│ │ └── ...
│ └── assets/
└── index.phpMeting-master/ 是 Meting-api 的 Node.js 源码仓库,仅用于参考或二次开发,不参与部署。实际运行时使用的是插件内 include/Meting.php(PHP 版本)。
第一步:安装 Meting Aplayer 插件
- 将
Meting Aplayer/文件夹上传至 Typecho 的usr/plugins/目录 - 将文件夹重命名为
Meting(这是必须的,插件内部通过pluginUrl.'/Meting/assets'引用资源) - 进入 Typecho 后台 → 控制台 → 插件,启用 "APlayer-Typecho | Meting"
- 确认服务器已安装 PHP 的
curl和openssl扩展
插件关键配置项(后台可调)
| 配置项 | 默认值 | 说明 |
|---|---|---|
| theme | #ad7a86 |
播放器主题色 |
| height | 340px |
播放列表最大高度 |
| autoplay | false |
是否自动播放 |
| order | list |
播放顺序(list / random) |
| preload | auto |
音频预加载策略 |
| bitrate | 192 |
音质(128 / 192 / 320) |
| api | 自动生成 | 云解析地址,一般无需修改 |
| salt | 自动生成 | API 接口保护盐值,一般无需修改 |
第二步:理解播放器的工作机制
插件激活后会自动注入以下前端资源到所有页面:
- header 钩子:注入
APlayer.min.css、APlayer.min.js,以及全局变量meting_api - footer 钩子:注入
Meting.min.js(负责发现 DOM 中的.aplayer元素并初始化播放器) - content 钩子:解析文章/页面内容中的
短代码,将其渲染为<div class="aplayer" ...>DOM 元素
因此,只要页面中存在带有正确 data-* 属性的 .aplayer 元素,Meting.min.js 就会自动将其初始化为播放器。
第三步:在 Jasmine 首页添加播放器
Jasmine 主题的首页模板是 index.php,它按顺序加载 header.php、left.php、navbar.php、文章列表、right.php、footer.php。
有两种方式将播放器嵌入首页:
方式 A:直接修改 index.php 模板(推荐)
编辑 Jasmine/index.php,在文章列表区域的上方或下方插入一个 .aplayer 容器。
注意:插入位置取决于那个区域是主题的哪个组件在负责,例如右边就查找包含right字段的文件,根据名称可定位具体位置,在对应的位置插入这一行即可
插入位置示例(在文章列表上方,导航栏下方):
<?php $this->need('template-parts/navbar.php'); ?>
<!-- ↓ 在这里插入播放器 ↓ -->
<div id="home-player"></div>
<!-- ↑ 插入结束 ↑ -->
<div class="container-fluid p-4 d-flex flex-column row-gap-4" id="index-content">
<?php if ($this->have()): ?>然后在 Jasmine/template-parts/footer.php 中($this->footer() 之前),添加初始化脚本:
<script>
document.addEventListener('DOMContentLoaded', function() {
var el = document.getElementById('home-player');
if (el && typeof APlayer !== 'undefined' && typeof meting_api !== 'undefined') {
var api = meting_api
.replace(':server', 'netease')
.replace(':type', 'playlist')
.replace(':id', '你的歌单ID')
.replace(':auth', '')
.replace(':r', Math.random());
var xhr = new XMLHttpRequest();
xhr.open('GET', api, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
new APlayer({
container: el,
mini: false,
autoplay: false,
lrcType: 3,
mutex: true,
preload: 'auto',
theme: '#ad7a86',
listMaxHeight: '340px',
order: 'list',
audio: data
});
}
};
xhr.send();
}
});
</script>将 你的歌单ID 替换为实际的歌单 ID(如网易云歌单 436843836)。平台和类型也可改为 tencent、kugou 等。
不显示播放列表:如需保留播放器面板但隐藏列表,可使用 CSS:在 Typecho 后台 → 外观 → 设置 → 自定义头部 HTML 中添加 <style>.aplayer .aplayer-list{display:none!important}</style>
方式 B:通过主题 customFooter 配置注入(无需改模板文件)
Jasmine 主题在后台提供了 customFooter 配置项,内容会被注入到 footer.php 第 12 行 $this->options->customFooter() 处。
在 Typecho 后台 → 外观 → 设置 → 自定义底部 HTML 中填入:
<div id="home-player"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var el = document.getElementById('home-player');
if (el && typeof APlayer !== 'undefined' && typeof meting_api !== 'undefined') {
var api = meting_api
.replace(':server', 'netease')
.replace(':type', 'playlist')
.replace(':id', '你的歌单ID')
.replace(':auth', '')
.replace(':r', Math.random());
var xhr = new XMLHttpRequest();
xhr.open('GET', api, true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
new APlayer({
container: el,
mini: false,
autoplay: false,
lrcType: 3,
mutex: true,
preload: 'auto',
theme: '#ad7a86',
listMaxHeight: '340px',
order: 'list',
audio: data
});
}
};
xhr.send();
}
});
</script>注意:这种方式下播放器会出现在页面 footer 区域,而非首页文章列表上方。如果只希望在首页显示,需要在脚本开头加判断:
if (window.location.pathname !== '/' && window.location.pathname !== '/index.php') return;方式 C:仅在首页文章内容中使用短代码(最简单但需创建特殊文章)
如果你有一个专门的"音乐"页面,可以在文章中直接写:
但这种方式不能直接用于首页文章列表区域,因为 index.php 渲染的是文章卡片摘要,不会展开文章正文中的短代码。此方式仅适用于单篇文章/页面的正文。
第四步:主题调整(可选)
图标大小调整(可选)。直接编辑 Jasmine/assets/main/main.css,修改以下已有规则的数值:
/* 第 60-65 行,左侧栏容器尺寸 */
#left .nav-link {
display: block;
width: 56px; /* 原 50px */
height: 56px; /* 原 50px */
color: rgba(var(--link-color-rgba));
}
/* 第 67-75 行,左侧栏图标大小 */
#left .nav-link i {
font-size: 28px; /* 原 24px */
padding-top: .75rem !important;
padding-bottom: .75rem !important;
padding-right: 1rem !important;
padding-left: 1rem !important;
border-radius: var(--bs-border-radius) !important;
transition: all .15s ease-in-out;
}手机端顶部导航栏和抽屉菜单的图标在 navbar.php 中通过 Bootstrap 的 fs-5 类控制大小,直接在 navbar.php 中将 fs-5 改为 fs-4 即可,或在 main.css 末尾追加:
/* 手机端导航图标(覆盖顶部栏、抽屉菜单、底部快捷入口) */
.navbar .nav-link i,
.offcanvas a i { font-size: 24px; }注意:抽屉菜单底部的页面图标(首页、归档、友链等)是裸 <a> 标签,不带 .nav-link 类,所以用 .offcanvas a i 统一覆盖。
第五步:音乐控制按钮侧边显示与移动端适配
Jasmine 主题的左侧栏底部(template-parts/left.php)有"切换模式"和"返回顶部"两个按钮。在它们上方添加一个音乐播放/暂停按钮,使用 Tabler Icons 的 ti-music(播放中)和 ti-music-off(已暂停)。
5.1 修改 template-parts/left.php
在底部 <ul> 中,"切换模式"按钮之前插入以下 <li>:
<ul class="nav flex-column nav-pills gap-0 row-gap-3 sticky-bottom bottom-0">
<!-- ↓ 新增音乐控制按钮 ↓ -->
<li class="nav-item d-flex justify-content-center position-relative" id="music-toggle-wrap" style="display:none!important;">
<a class="nav-link p-0 d-flex align-items-center justify-content-center" id="music-toggle"
href="javascript:void(0)" title="播放音乐">
<i class="ti ti-music px-3 py-1 rounded" id="music-toggle-icon"></i>
</a>
<span class="position-absolute nav-item-title text-nowrap" id="music-toggle-title">播放音乐</span>
</li>
<!-- ↑ 新增结束 ↑ -->
<li class="nav-item d-flex justify-content-center position-relative">
<a class="nav-link p-0 d-flex align-items-center justify-content-center" id="bd-theme"按钮默认隐藏(style="display:none!important"),等播放器初始化成功后再显示。
5.2 修改播放器初始化脚本
将第三步中的初始化脚本替换为以下版本(同时负责初始化播放器和绑定按钮事件):
<script>
document.addEventListener('DOMContentLoaded', function() {
var el = document.getElementById('home-player');
if (!el || typeof APlayer === 'undefined' || typeof meting_api === 'undefined') return;
var api = meting_api
.replace(':server', 'netease')
.replace(':type', 'playlist')
.replace(':id', '你的歌单ID')
.replace(':auth', '')
.replace(':r', Math.random());
var xhr = new XMLHttpRequest();
xhr.open('GET', api, true);
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4 || xhr.status !== 200) return;
var data = JSON.parse(xhr.responseText);
var ap = new APlayer({
container: el,
mini: false,
autoplay: false,
lrcType: 3,
mutex: true,
preload: 'auto',
theme: '#ad7a86',
listMaxHeight: '340px',
order: 'list',
audio: data
});
// 暴露到全局,供按钮和 PJAX 回调使用
window.homeAPlayer = ap;
// 显示控制按钮
var wrap = document.getElementById('music-toggle-wrap');
if (wrap) wrap.style.display = '';
// 绑定按钮点击事件
var btn = document.getElementById('music-toggle');
var icon = document.getElementById('music-toggle-icon');
var title = document.getElementById('music-toggle-title');
if (btn) {
btn.addEventListener('click', function() {
ap.toggle();
});
}
// 监听播放/暂停事件,切换图标
ap.on('play', function() {
if (icon) {
icon.classList.remove('ti-music-off');
icon.classList.add('ti-music');
}
if (title) title.textContent = '暂停音乐';
});
ap.on('pause', function() {
if (icon) {
icon.classList.remove('ti-music');
icon.classList.add('ti-music-off');
}
if (title) title.textContent = '播放音乐';
});
};
xhr.send();
});
</script>5.3 手机端适配
左侧栏在手机端被 d-none d-lg-block 完全隐藏,因此需要在 navbar.php 的手机端按钮区域中也添加一个音乐控制按钮。
编辑 Jasmine/template-parts/navbar.php,找到第 44 行的 <div class="d-flex d-block d-lg-none">,在主题切换按钮和汉堡菜单按钮之间插入:
<div class="d-flex d-block d-lg-none">
<a class="nav-link p-0 d-flex align-items-center justify-content-center" id="bd-theme"
href="javascript:changeBsTheme()">
<i class="ti ti-sun-moon px-3 py-1 rounded fs-5"></i>
</a>
<!-- ↓ 新增手机端音乐控制按钮 ↓ -->
<a class="nav-link p-0 d-flex align-items-center justify-content-center d-lg-none" id="music-toggle-mobile"
href="javascript:void(0)" title="播放音乐" style="display:none;">
<i class="ti ti-music px-3 py-1 rounded fs-5" id="music-toggle-icon-mobile"></i>
</a>
<!-- ↑ 新增结束 ↑ -->
<button class="navbar-toggler border-0 pe-0" type="button" ...>然后在播放器初始化脚本中,增加对手机端按钮的绑定。在 ap.on('pause', ...) 回调之后添加:
// 手机端按钮绑定
var btnMobile = document.getElementById('music-toggle-mobile');
var iconMobile = document.getElementById('music-toggle-icon-mobile');
if (btnMobile) {
btnMobile.style.display = '';
btnMobile.addEventListener('click', function() { ap.toggle(); });
}
ap.on('play', function() {
if (iconMobile) {
iconMobile.classList.remove('ti-music-off');
iconMobile.classList.add('ti-music');
}
});
ap.on('pause', function() {
if (iconMobile) {
iconMobile.classList.remove('ti-music');
iconMobile.classList.add('ti-music-off');
}
});5.4 工作原理
- 播放器初始化成功后,脚本将 APlayer 实例挂载到
window.homeAPlayer - 同时将
#music-toggle-wrap的display设为空,使按钮可见 - 点击按钮调用
ap.toggle()切换播放/暂停 - 通过 APlayer 的
play和pause事件同步切换图标:播放中显示ti-music,暂停时显示ti-music-off - 鼠标悬停在按钮上时,左侧弹出的提示文字也会动态更新("播放音乐" / "暂停音乐")
第六步:PJAX 兼容(如适用)
如果 Jasmine 主题启用了 PJAX(页面无刷新切换),播放器在页面切换后不会自动销毁和重建。需要在主题的 PJAX 回调中添加:
// 页面切换前销毁播放器
if (typeof aplayers !== 'undefined') {
for (var i = 0; i < aplayers.length; i++) {
try { aplayers[i].destroy(); } catch(e) {}
}
}
// 页面加载后重新初始化
if (typeof loadMeting === 'function') {
loadMeting();
}快速验证清单
- Meting 插件文件夹已命名为
Meting并放在usr/plugins/下 - 插件已在 Typecho 后台启用
- 服务器有
curl和opensslPHP 扩展 - 首页源码中能看到
<div class="aplayer" ...>元素 - 浏览器控制台无 JS 报错
- 播放器能正常加载歌曲列表并播放
支持的音乐平台与资源类型
| 平台 | code | 单曲 | 专辑 | 歌单 | 歌手 |
|---|---|---|---|---|---|
| 网易云音乐 | netease |
song | album | playlist | artist |
| QQ 音乐 | tencent |
song | album | playlist | artist |
| 酷狗音乐 | kugou |
song | album | playlist | artist |
示例:播放网易云歌单
示例:播放自定义音频
评论