为Fluid主题简单添加PJAX支持
JimmyQin 博主

一点微小的工作,初步实现无刷新加载。

本教程仅在Fluid主题1.8.1版本测试通过。

pjax

一、介绍

pjax是什么?

pjax 结合 pushState 和 ajax 技术(PJAX=history.pushState+ajax), 不需要重新加载整个页面就能从服务器加载 Html 到你当前页面,这个 ajax 请求会有永久链接、title 并支持浏览器的回退/前进按钮。

简单来说pjax就是无刷新加载,看起来似乎很高端,但其实很多网站都已经在使用和pjax类似的技术,比如百度搜索:在搜索页更换关键词搜索,页面只是部分内容重载。

pjax的优点和好处很多,仅就个人博客而言,最直观的体验就是能够实现页面平滑切换和音乐不间断播放

pjax效果演示:http://pjax.herokuapp.com
~~ 或者就在本站体验。 ~~

pjax这般优秀,奈何本站使用的如此好看的Fluid主题竟然不支持,只好自己动手,慢慢摸索和折腾一下。

二、安装

1、版本选用

ONE.jquery-pjax
TWO.Moox-pjax

第一个是需要使用jquery依赖的版本,俩版本大同小异,只是后者代码更新日期较新,在这里我选用了后者。

推荐首先阅读下官方文档

2、引入js

/主题目录/layout/partial/footer.ejs中加入

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

来引入pjax;

或者使用npm安装本地后引用

1
$ npm install pjax
1
<script src="./node_modules/pjax/pjax.js"></script>

现在,我们已经安成了pjax的安装,本地预览一下,页面跳转已初见成效。但你可能会发现,标题消失、图片失效等等各项功能异常。别着急,这是由于部分js未能加载导致的,稍后会解决。

三、使用

1、功能配置

/主题目录/layout/layout.ejs中插入代码:

1
2
3
4
5
6
7
8
9
10
<script>
// pjax
var pjax = new Pjax({
selectors: [
"title", //加载标题
"main", //加载主体框架部分
"header", //加载头部(文章页头图等)
]
})
</script>

elements选择触发器,即点击什么来触发pjax(只能用a或者form),a为链接。
selectors根据css选择器来选择更新的节点(即当触发elements时哪些内容会刷新,其余部分保持不变)

有用的pjax函数

1
2
3
4
pjax.loadUrl();
document.addEventListener('pjax:send', function () {});
document.addEventListener('pjax:complete', function () {});
document.addEventListener('pjax:error', function () {});

2、项目优化

2.1 Valine评论重载

在Fluid1.8.1版本中已经解决了 pjax刷新后发现评论不能加载 这个问题,如果使用1.8.0及以下版本需要进行下面的操作。
/主题目录/layout/layout.ejs中插入代码:

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
//加载valine
function LoadValine(){
$.getScript("https://cdn.staticfile.org/valine/1.4.14/Valine.min.js", function() {

// 生成评论的代码
var GUEST_INFO = ['nick','mail','link'];
var guest_info = '<%= theme.valine.meta %>'.split(',').filter(function(item){
return GUEST_INFO.indexOf(item) > -1
});
var valine = new Valine();
valine.init({
el: "#vcomments",
guest_info: guest_info,
app_id: "<%= theme.valine.appid %>",
app_key: "<%= theme.valine.appkey %>",
placeholder: "<%= theme.valine.placeholder %>",
path: <%= theme.valine.path %>,
avatar: "<%= theme.valine.avatar %>",
meta: <%- JSON.stringify(theme.valine.meta || []) %>,
pageSize: "<%= theme.valine.pageSize %>",
lang: "<%= theme.valine.lang %>",
highlight: <%= theme.valine.highlight %>,
recordIP: <%= theme.valine.recordIP %>,
serverURLs: "<%= theme.valine.serverURLs %>"
})
});
};

然后进行这个函数的重载

1
2
3
document.addEventListener('pjax:complete', function (){
LoadValine();
});

如果在自建页面使用了Valine评论,仍需要添加//加载valine函数,但是请将重载指令放在评论所在页面的.md文件中,避免出现评论重复加载现象。同时为了保证在该页面刷新时重载评论,需要使用pjax的load函数。
完整示例如下:

1
2
3
4
5
6
7
8
9
<!-- pjax完成/监听刷新加载Valine -->
<script>
document.addEventListener('pjax:complete', function (){
LoadValine();
});
window.addEventListener('load',function(){
LoadValine();
});
</script>

然而,这样操作以后,还是会出现一些bug:在文章页评论加载完毕以后,用户跳转留言页,再返回到刚刚访问的文章页时,会出现评论重复的现象。我还在寻找修复方法,但是一般访问情景应该不会有特别大的影响。
(谁会在页面之间反复横跳呢?)

2.2 懒加载修复

/主题目录/layout/layout.ejs中添加重载函数如下:

1
2
3
    document.addEventListener('pjax:complete', function (){
$.getScript("/js/lazyload.js");
});

2.3 下滑箭头、抖动等修复

/主题目录/layout/layout.ejs中插入代码:

1
2
3
4
5
6
7
8
9
document.addEventListener('pjax:complete', function (){
$.getScript("/js/main.js");
$.getScript("/js/debouncer.js");
});

// 窗口监听load(加载、刷新)事件,执行函数
window.addEventListener('load',function(){
$.getScript("/js/main.js");
});

2.4 FancyBox重载

/主题目录/layout/layout.ejs中插入代码:

1
2
3
4
5
6
7
8
9
10
11
  //加载FancyBox
function LoadFancyBox(){
$('#post img:not(.no-zoom img, img[no-zoom]), img[zoom]').each(
function () {
var element = document.createElement('a');
$(element).attr('data-fancybox', 'images');
$(element).attr('href', $(this).attr('src'));
$(this).wrap(element);
}
);
};

然后进行这个函数的重载

1
2
3
4
document.addEventListener('pjax:complete',
function (){
LoadFancyBox();
});

bug:在关闭放大的图片后,页面会漂移。
我暂时关闭了这个功能。

2.5 修复MarkDown样式丢失

Fluid1.8.1的更新中,强哥加入判断以减少不必要的加载项,但加入pjax之后判断似乎失效了,那么就干脆不要判断好了(反向升级)
/主题目录/layout/_partial/css.ejs中的<% if (is_post() || is_page()) { %>判断删除即可。

2.6 加入加载动画

css如下:

1
2
3
4
5
6
7
8
.loading{display:none}
.loading{height:100%;width:100%;position:fixed;top:0;left:0;z-index:999999;background-color:rgba(250,250,250,.9)}
.loading img{width: 280px;height:210px;position: relative;top: 45%;left: 50%;margin-left:-140px;margin-top: -105px;}
#loader{display: block; position: relative; left: 50%; top: 50%; width: 150px; height: 150px; margin: -75px 0 0 -75px; border-radius: 50%; border: 3px solid transparent; border-top-color: #ff5a5a; -webkit-animation: spin 1s linear infinite; animation: spin 1s linear infinite;}
#loader:before{content: ""; position: absolute; top: 5px; left: 5px; right: 5px; bottom: 5px; border-radius: 50%; border: 3px solid transparent; border-top-color: #5af33f; -webkit-animation: spin 3s linear infinite; animation: spin 3s linear infinite;}
#loader:after{content: ""; position: absolute; top: 15px; left: 15px; right: 15px; bottom: 15px; border-radius: 50%; border: 3px solid transparent; border-top-color: #6dc9ff; -webkit-animation: spin 2s linear infinite; animation: spin 2s linear infinite;}
@-webkit-keyframes spin{0%{-webkit-transform: rotate(0deg); -ms-transform: rotate(0deg); transform: rotate(0deg);} 100%{-webkit-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg);}}
@keyframes spin{0%{-webkit-transform: rotate(0deg); -ms-transform: rotate(0deg); transform: rotate(0deg);} 100%{-webkit-transform: rotate(360deg); -ms-transform: rotate(360deg); transform: rotate(360deg);}}

pjax载入动画:

1
2
3
4
5
6
7
8
  // 开始 PJAX 执行的函数
document.addEventListener('pjax:send', function (){
$(".loading").css("display", "block");//加载转圈圈的css
});

// PJAX 完成之后执行的函数,可以和上面的重载放在一起
document.addEventListener('pjax:complete', function (){
$(".loading").css("display", "none");

另外推荐一下Nprogress.js也很好看。

四、本站pjax完整代码

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
<script>
// pjax
var pjax = new Pjax({
selectors: [
"title",
"main",
"header",
]
})

//加载valine
function LoadValine(){
$.getScript("https://cdn.staticfile.org/valine/1.4.14/Valine.min.js", function() {

// 生成评论的代码
var GUEST_INFO = ['nick','mail','link'];
var guest_info = '<%= theme.valine.meta %>'.split(',').filter(function(item){
return GUEST_INFO.indexOf(item) > -1
});
var valine = new Valine();
valine.init({
el: "#vcomments",
guest_info: guest_info,
app_id: "<%= theme.valine.appid %>",
app_key: "<%= theme.valine.appkey %>",
placeholder: "<%= theme.valine.placeholder %>",
path: <%= theme.valine.path %>,
avatar: "<%= theme.valine.avatar %>",
meta: <%- JSON.stringify(theme.valine.meta || []) %>,
pageSize: "<%= theme.valine.pageSize %>",
lang: "<%= theme.valine.lang %>",
highlight: <%= theme.valine.highlight %>,
recordIP: <%= theme.valine.recordIP %>,
serverURLs: "<%= theme.valine.serverURLs %>"
})
});
};

//pjax开始时加载函数
document.addEventListener('pjax:send', function (){
$(".loading").css("display", "block");//加载转圈圈的css
});

// pjax加载结束后执行函数
document.addEventListener('pjax:complete', function (){
$(".loading").css("display", "none");
$.getScript("/js/lazyload.js");
$.getScript("/js/main.js");
$.getScript("/js/debouncer.js");
});

// 窗口监听load(加载、刷新)事件,执行函数
window.addEventListener('load',function(){
$.getScript("/js/main.js");
});

</script>

五、To Do List

以下功能暂时还没有修复,后期慢慢研究,也期待有大佬提供解决方案。

代码高亮和复制按钮
Valine评论重复问题
FancyBox漂移问题
Typed.js文本打字机
Toc.js文章目录
anchor锚点
其他评论系统
Editor.md编辑器

六、后记

参考文章:
https://www.jianshu.com/p/557cad38e7dd
https://inkss.cn/article/other/80b5f235.html
感谢:lluuiqMoMik 对本站pjax实现过程中的指导和帮助。
由于个人能力实在有限,导致bug多多,还是期待Fluid官方支持pjax。

  • 本文标题:为Fluid主题简单添加PJAX支持
  • 本文作者:JimmyQin
  • 创建时间:2020-06-28 10:58:37
  • 本文链接:https://jimmyqin.com/posts/34250.html
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论