CnSywFRD
文章6
标签9
分类2
<% if (options.search.type == 'local') { %> <%- js_auto_version('js/search') %> <% } %> <% if (options.search.type=='swiftype') { %> <% } %>

文章分类

一言

文章归档

hexo新版nexmoe主题加入aplayer 引入pjax防止切换页面刷新【FRD 01】

hexo新版nexmoe主题加入aplayer 引入pjax防止切换页面刷新【FRD 01】

前言

加入aplayer(metingJS)实现在网页右下角添加播放器后,出现了切换页面刷新后音乐中断,进度丢失的问题,进而需要引入pjax实现切换页面不刷新

参考来源:Aplayer+MetingJS+Pjax=网“页”云音乐

但是文章中使用layout布局文件是完整的ejs文件,而新版的nexmoe主题(大约是4.1.5后)已经将其拆分成了多个文件,其中layout变成了jsx文件,目录结构也有所改变
目录结构

经过尝试已经完成修改并成功完成,(大)部分代码来源于Deepseek,简单做一下分享

2025.05.31更新:原有方法对模板文件破坏太大,存在低级问题且不易维护,现已重构代码

新的代码使用aplayer原生播放模式,如果需要利用meting.js可以参考下文中旧的代码

修改部分(新)

自定义js

初始化播放器和pjax

把下面这个文件放在/source/js/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// 全局播放器实例
let globalPlayer = null;

// 初始化播放器
function initPlayer() {
if (!globalPlayer) {
globalPlayer = new APlayer({
container: document.getElementById('aplayerallpages'),
fixed: true,
autoplay: false,
theme: '#FADFA3',
loop: 'all',
order: 'random',
preload: 'auto',
volume: 0.7,
mutex: true,
lrcType: 0,
audio: [{name: 'example1',artist: 'example',url: '/music/example1.mp3',cover:'cover1.png'},
{name: 'example2',artist: 'example',url: '/music/example2.mp3',cover:'cover2.png'}]
});
}
return globalPlayer;
}

// 初始化 PJAX
function initPjax() {
$(document).pjax('a:not([target="_blank"], .no-pjax)', '#pjax-container', {
fragment: '#pjax-container',
timeout: 8000
});
}

// DOM 就绪后初始化
document.addEventListener('DOMContentLoaded', function() {
initPlayer();

// 确保 PJAX 依赖已加载
if (window.$ && $.fn.pjax) {
initPjax();
} else {
console.warn('PJAX 依赖未加载');
}
});

$(document).on('pjax:complete', function(event) {
reloadSidebarMenu();
});

function reloadSidebarMenu() {
$.ajax({
url: window.location.href,
type: 'GET',
dataType: 'html',
success: function(fullPageHtml) {
// 从完整页面中提取侧边栏菜单
const $newContent = $(fullPageHtml);
const newMenu = $newContent.find('#mlist-container').html();

// 更新侧边栏容器
$('#mlist-container').html(newMenu);

// 重新初始化 MDUI 组件(如果需要)
if (window.mdui) {
mdui.mutation();
}
},
error: function() {
console.error('Failed to reload sidebar menu');
}
});
}

主题配置文件

即博客根目录下的_config.nexmoe.yml

注意:jquery和pjax一定要使用这两个版本,不然有可能无法加载

来源:pjax实现网站无刷新化和个人遇到的无数坑

1
2
3
4
5
6
7
8
slotHead: |   
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/aplayer/1.10.1/APlayer.min.css">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery.pjax/2.0.1/jquery.pjax.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/aplayer/1.10.1/APlayer.min.js"></script>
<script src="/js/上面自定义的.js"></script>
slotFooter: |
<div id="aplayerallpages">

content.jsx

主题自带的劫持功能没办法作用到包含刷新页面代码的文件,因此需要修改content.jsx

文件在/node_modules/hexo-theme-nexmoe/layout/_layout/nexmoe

稍作修改套一层pjax容器即可

1
2
3
4
5
6
7
8
return (
<div id="pjax-container" data-pjax-container>
<div
class="nexmoe-primary"
dangerouslySetInnerHTML={{ __html: body }}
></div>
</div>
);

header.ejs

为了同步更新侧边导航栏的高亮部分,我们的自定义js有更新#mlist-container的内容

需要把高亮部分的代码用这个容器框起来

此文件在/node_modules/hexo-theme-nexmoe/layout/_layout/nexmoe

1
2
3
4
5
6
7
8
9
10
11
12
<div id="mlist-container">
<div class="nexmoe-list mdui-list" mdui-collapse="{accordion: true}">
<% for (name in theme.menu) { %>
<a class="nexmoe-list-item mdui-list-item mdui-ripple <%= is_current(theme.menu[name][0]) %>" href="<%- url_for(theme.menu[name][0]) -%>" title="<%= name %>">
<i class="mdui-list-item-icon nexmoefont <% if (theme.menu[name][1]){ %><%= theme.menu[name][1] %><%} else{ %><%= 'icon-unorderedlist' %><% } %>"></i>
<div class="mdui-list-item-content">
<%= name %>
</div>
</a>
<% } %>
</div>
</div>

完成

1
hexo g & hexo d

然后就OK啦

旧代码存档

以下文件都在/你的博客/node_modules/hexo-theme-nexmoe/layout/

layout.jsx

由于包含跳转页面的代码在layout.jsx中,因此无法使用hexo自带的劫持功能,需要修改layout.jsx

文件头部

1
2
3
4
5
const PJAX_CONFIG = {
selectors: ['#pageContent'], // 指定内容替换容器```
excludes: '#aplayerContent, .mdui-drawer', // 排除播放器和侧边栏
timeout: 8000
};

中部

1
2
3
4
5
6
7
8
9
10
11
12
return (
<html lang={language ? language.substr(0, 2) : ''}>
<head
dangerouslySetInnerHTML={{
__html: partial('_partial/head') +
'<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css"/>' +
'<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>' + // 新增 jQuery
'<script src="https://cdn.jsdelivr.net/npm/pjax@0.2.8/pjax.min.js"></script>' + // 新增 PJAX
'<script src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>' +
'<script src="https://cdn.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js"></script>'
}}
></head>

如果需要修改播放器css样式,上面的https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css需要改成自己的css文件地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<SearchBox {...this.props} />
<div
dangerouslySetInnerHTML={{
__html: theme.slotFooter
}}
></div>
<div id="aplayerContent">
<meting-js server="netease" type="playlist" id="your id" fixed="true" order="random" list-max-height="1000px" lrc-type="1" data-pjax-persist></meting-js>
</div>
<script dangerouslySetInnerHTML={{
__html: `
document.addEventListener('DOMContentLoaded', function() {
// 初始化 PJAX
var pjax = new Pjax(${JSON.stringify(PJAX_CONFIG)});

// 页面切换后保持播放器
document.addEventListener('pjax:end', function() {
if(window.aplayers && window.aplayers.length > 0) {
window.aplayers[0].toggle();
}
});

// 重新初始化 MetingJS
document.addEventListener('pjax:complete', function() {
if(typeof Meting !== 'undefined') {
Meting.reload();
}
});
});
`
}}></script>
</body>

background.jsx

这个在/layout/_partial

<div id="nexmoe-background"></div> 里面的内容全都套在<div id="pageContent"></div>

1
2
3
4
5
6
<a
href={url_for()}
title={config.author || config.title}
class="mdui-btn mdui-btn-icon"
data-pjax // 新增属性
>

searchbox.jsx

也在/layout/_partial

同样在<div id="nexmoe-search-space"></div>外面套个<div id="pageContent"></div>

中间

1
2
3
4
5
6
7
<input
class="search-input"
type="text"
placeholder={ __('search')}
onInput="sinput();"
data-no-pjax // 新增属性
/>

body.jsx

此文件在layout/_layout/nexmoe

需要在<Fragment>里面<div id="nexmoe-header"></div>外面套一层
<div id="pageContent" data-pjax-container></div>

大功告成

其实挺简单的对吧,但是我对前端一点都不熟,自己一个人搞了8小时现在是15小时了