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; }
function initPjax() { $(document).pjax('a:not([target="_blank"], .no-pjax)', '#pjax-container', { fragment: '#pjax-container', timeout: 8000 }); }
document.addEventListener('DOMContentLoaded', function() { initPlayer(); 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); 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> );
|
为了同步更新侧边导航栏的高亮部分,我们的自定义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>
|
完成
然后就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/[email protected]/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/[email protected]/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(); } });
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小时了