Hexo 主题兼容 Pjax

什么是 Pjax

​Pjax​​​ 通过 Ajax 从服务器获取 HTML 内容,然后用加载到的 HTML 替换页面上容器元素的内容。Pjax 使用 pushState 更新浏览器中的当前 URL,即 ​​pjax = pushState + ajax​​ 。最早的时候,​​Pjax​​​ 是一个基于 ​​jQuery​​ 的插件,后来推出了完全独立的版本,适用更广泛的应用场景。值得一提的是,Pjax 最大的优势在于,可以在网站本身无刷新的情况下,局部刷新页面内容,同时在现代浏览器中支持前进和后退,由于局部加载的数据量极小,加载速度极快,因此可以最大程度地提升用户体验。Pjax 的天生劣势在于,默认配置对 ​​SEO​​ 并不友好,同时非常依赖页面布局的一致性,需要大量改造来优化。

Hexo 引入 Pjax

很多较早使用 ​​Pjax​​ 的 Hexo 主题,都使用了基于 jQuery 的版本。因此如果是新引入,可以使用最新独立版本的 ​​Pjax​​

1
<script src="https://cdn.jsdelivr.net/npm/pjax@VERSION/pjax.min.js"></script>

为什么引入 Pjax

由于想在 Hexo 博客中整合 Aplayer 音乐播放器,但是如果不进行改造,跳转页面肯定会引起音乐播放的中断,于是就想到利用 ​​Pjax​​ 的特性,局部加载核心内容,从而不影响音乐播放器,整体效果类似网易云音乐的 PC 端。

兼容处理

首先独立版的 Pjax 工作方式其实特别好理解。例如初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
document.addEventListener('DOMContentLoaded', function () {
pjax = new Pjax({
elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"]):not([pjax-fancybox]):not([notallow="return false;"]):not([notallow="return!1"]):not([target="_blank"]):not([target="view_window"]):not([href$=".xml"])',
selectors: [
"head title", // 标题
"head meta[name=keywords]", // 关键词
"head meta[name=description]", // 描述
".pjax",
"pjax", // <pjax></pjax> 标签
"script[data-pjax], .pjax-reload script" // script 标签添加 data-pjax 或 script 标签外层添加 .pjax-reload 的 script 代码段重载
],
cacheBust: <%= theme.plugins.pjax.cacheBust %>, // url 地址追加时间戳,用以避免浏览器缓存
timeout: <%= theme.plugins.pjax.timeout %>,
});
});

然后是标签部分,主要是用在以下场景:

1
2
3
4
5
6
7
8
<div class="pjax">我是将被 Pjax 重载的内容</div>
<script data-pjax>我是将被 Pjax 重载的内容</script>
<div class="pjax-reload">
<div>
<div>我不是将被 Pjax 重载的内容</div>
<script>我是将被 Pjax 重载的内容</script>
</div>
</div>

常见问题

Pjax 触发重载

这个是最严重的问题,独立版的 ​​Pjax​​ 会自动检测页面布局变化,如果变化过大,则会直接重载整个页面。实际测试就发现 Hexo 非常容易触发重载,尤其是 ​​page​​​​​post​​ ,因为这两种页面原本的处理就完全不同。测试了一下,如果完全相同,则不会触发重载。

自定义 JS 代码不加载

启用 Pjax 以后,可能会出现一些 JavaScript 代码加载不出来的情况。解决方案很简单,只要在原有的 <script></script> 标签中添加 data-pjax 属性就行。

1
2
3
<script data-pjax type="text/javascript">
// Some code here
</script>

参考资料