我发现 Pjax 能极大增加页面切换的流畅度。于是我着手适配。
参考文章:
初步实现
原理
Pjax 拦截用户的跳转请求,用 Ajax 使页面局部更新使页面无需完全重载。
选择
前者依赖 jQuery。我选择后者。
分析
hexo-theme-icarus 主题在更改页面时,会更改的内容有:
title
标题head
元素内的一些 meta
信息什么的.navbar-start
和 .navbar-start
顶栏的几个选项的高亮.columns
文章和插件#back-to-top
返回页顶的按钮
设置并初始化 Pjax
source/js/SetPjax.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| var pjax = new Pjax({ selectors: [ "head title", ".columns", ".navbar-start", ".navbar-end", ".searchbox", "#back-to-top", ".pjax-reload" ], });
function pjax_reload() { }
document.addEventListener("pjax:complete", function () { pjax_reload(); });
|
脚本中添加了 .pjax-reload
和 [data-pjax]
。若切换页面时,某些元素需重新加载,可添加 .pjax-reload
到该元素,脚本可添加 [data-pjax]
属性。
利用 Hexo 注入器功能引入 Pjax 和初始化脚本:
scripts/inject.js1 2 3 4 5 6 7 8 9
| const js = hexo.extend.helper.get('js').bind(hexo);
hexo.extend.injector.register('head_end', () => { return js('//lib.baomitu.com/pjax/0.2.8/pjax.min.js'); });
hexo.extend.injector.register('head_end', () => { return js('/js/SetPjax.js'); });
|
一些问题
现在 Pjax 的适配已经基本完成,切换页面明显顺畅了许多。 但仍有一些 hexo-theme-icarus 主题相关的问题:
只要找到相关函数并添加到需要重新执行的函数
内即可解决问题。奈何我能力有限,我暂且先去 Github 询问主题作者相关信息。
改进
提交更改至主题。
配置文件相关
include/schema/plugin/pjax.json1 2 3 4 5 6 7
| + { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "/plugin/pjax.json", + "description": "Enable PJAX", + "type": "boolean", + "default": true + }
|
欲加载的标签打上标记
layout/common/scripts.jsx1 2 3 4 5 6 7 8 9
| @@ -35,9 +35,9 @@ module.exports = class extends Component { {clipboard && <script src={cdn('clipboard', '2.0.4', 'dist/clipboard.min.js')} defer></script>} <script dangerouslySetInnerHTML={{ __html: `moment.locale("${language}");` }}></script> <script dangerouslySetInnerHTML={{ __html: embeddedConfig }}></script> - <script src={url_for('/js/column.js')}></script> + <script data-pjax src={url_for('/js/column.js')}></script> <Plugins site={site} config={config} page={page} helper={helper} head={false} /> - <script src={url_for('/js/main.js')} defer></script> + <script data-pjax src={url_for('/js/main.js')} defer></script>
|
layout/plugin/back_to_top.jsx1 2 3 4 5 6 7 8 9
| @@ -9,7 +9,7 @@ class BackToTop extends Component { <a id="back-to-top" title={title} href="javascript:;"> <i class="fas fa-chevron-up"></i> </a> - <script src={jsUrl} defer></script> + <script data-pjax src={jsUrl} defer></script> </Fragment>;
}
|
新增 PJAX 插件
layout/plugin/pjax.jsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @@ -0,0 +1,18 @@ + const { Component, Fragment } = require('inferno'); + + class Pjax extends Component { + render() { + if (this.props.head) { + return null; + } + const { helper } = this.props; + const { url_for, cdn } = helper; + + return <Fragment> + <script src={cdn('pjax', '0.2.8', 'pjax.min.js')}></script> + <script src={url_for('/js/pjax.js')}></script> + </Fragment>; + } + } + + module.exports = Pjax;
|
初始化脚本
source/js/pjax.js1 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
| @@ -0,0 +1,36 @@ + // eslint-disable-next-line no-unused-vars + let pjax; + + function initPjax() { + try { + // eslint-disable-next-line no-undef + pjax = new Pjax({ + selectors: [ + 'head title', + '.columns', + '.navbar-start', + '.navbar-end', + '.searchbox', + '#back-to-top', + '[data-pjax]', + '.pjax-reload' + ] + }); + } catch (e) { + console.warn('PJAX error: ' + e); + } + } + + // // Listen for start of Pjax + // document.addEventListener('pjax:send', function() { + // return; + // // TODO pace start loading animation + // }) + + // // Listen for completion of Pjax + // document.addEventListener('pjax:complete', function() { + // return; + // // TODO pace stop loading animation + // }) + + window.addEventListener('DOMContentLoaded', () => initPjax());
|