PJAX加速站点访问

说起 PJAX,已是由来已久,在很多网站上经常会遇到。它通过 PushState + Ajax 技术,实现 HTML 页面局部刷新等功能,提供了一种极速的浏览体验。避免每次载入过多的重复资源,耗费额外加载时间,提升了网站的整体访问速度。最直观的体验就是音乐能全局播放了!

Tips:本站集成的 PJAX 功能会随着 v2.2 版本一起发布!

在 Github 上,PJAX 用的最多的主要是这两版:defunkt/jquery-pjaxMoOx/pjax

defunkt/jquery-pjax

依赖 JQuery,最近更新停留在三年前,文档介绍有服务端配置:

1
2
3
4
5
6
7
8
# Server-side configuration
# Ideally, your server should detect pjax requests by looking at the special X-PJAX HTTP header, and render only the HTML meant to replace the contents of the container element (#pjax-container in our example) without the rest of the page layout. Here is an example of how this might be done in Ruby on Rails:

def index
if request.headers['X-PJAX']
render :layout => false
end
end

不过按操作配置完后,在我的网站效果不是很好,网上也没找到解决办法,没提到服务端配置啥的,多次尝试无果后,我也就放弃了。感兴趣的朋友可以试一下,这里贴上几篇参考文章

PJAX站点加速之翼

PJAX原理和使用

typecho实现pjax

整合PJAX网页无刷新,支持评论和搜索…

MoOx/pjax (重点介绍)

去除了 JQuery 依赖,其它功能和上一个类似。网上教程不是很多,这篇 倒是可以参考下。高版本 NEXT 集成的 PJAX 也是这个。

本站 HEXO:v3.9,NEXT:v5.1.4,升级可不是件容易的事,想想还是自己折腾吧!

  1. 首先,参照官方,在主题 _config.yml 文件中配置
1
2
3
# https://github.com/MoOx/pjax
pjax:
enable: true
  1. 在 next/layout/_custom/ 新建 pjax.swig,内容如下
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
<div class="pjax_loading">
<div id="pjax_loader"></div>
</div>

<!-- https://github.com/MoOx/pjax -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/pjax.min.js"></script>
<script type="text/javascript">

var pjax = new Pjax({
elements: 'a',
selectors: [
'title',
'.content-wrap',
'.sidebar-inner'
],
analytics: false,
cacheBust: false,
debug: false,
});

$(document).on('pjax:send', function() {
loadingBefore(); // 加载动画
});

$(document).on('pjax:success', function() {
loadingAfter(); // 加载动画
});

function loadingBefore(){
$("#main").fadeOut(100);
$(".pjax_loading").css("display", "block");

}

function loadingAfter(){
var styl = '{{theme.pjax.style}}';
$("#main").fadeIn(100);
$(".pjax_loading").css("display", "none");
}

</script>
  1. 在 next/layout/_custom/custom.swig 或者 next/layout/_layout.swig 中引入 pjax.swig
1
2
3
{% if theme.pjax.enable %}
{% include 'pjax.swig' %}
{% endif %}

这样配置后,网站已经初步具备 PJAX 功能了,那么接下来,就是要处理一大堆兼容的事情!

灵感来源

刚开始想着按照 NEXT 高版本 PJAX 的代码来就行了,可后来发现版本间变动太大,要找起这个功能来还真不容易。后来发现也有 NEXT 5 版的主题整合了 PJAX 功能,如 Sagiri pjaxLeesin’s Blog 给了我一定启发。前一位将部分依赖整成 NodeJS 的 node_modules 进行引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
require('./utils');
require('./motion');
require('./affix');
require('./pisces')();
require('./scrollspy');
require('./post-details')();
require('./bootstrap');
require('./evanyou');
require('./leancloud')();
require('./share')();
require('./scroll');
require('./since');
require('./title');
require('./type');
require('./kanban');
require('./mix');
require('./clipboard');
require('./pjax');
require('./online');
require('./search');

不会 NodeJS 还真看不明白,后一位则将 JS 代码重新复制了一份,耦合性太高了,虽然后期改用 RequireJS。不过吧,文章整体逻辑太乱,看着真的很懵,还是自己想办法吧!

柳暗花明

一篇 NEXT 作者的 文章 引起了我的注意,看来很多主题都是类 EJS,代码相似度都挺高。多次调试代码后,终于对其渲染逻辑有了一定了解,一周多的折腾总算告一段落,再整都 HEXO 底层了。(⊙﹏⊙)b

进入网站首页,会加载很多 JS/CSS 等等,其它页面无需再次加载,直接引用即可,这就是 PJAX 要做的事情了。然而 NEXT 很多 JS 都是使用 $(document).ready(function(){...}) 这种写法(DOM 树加载完执行),所以我们需要将这些方法提取出来,使其在别的地方能被调用到,以 next/source/js/src/schemes/pisces.js 这个 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
$(document).ready(function () {

var sidebarInner = $('.sidebar-inner');

initAffix();
resizeListener();

function initAffix () {
var headerOffset = getHeaderOffset(),
footerOffset = getFooterOffset(),
sidebarHeight = $('#sidebar').height() + NexT.utils.getSidebarb2tHeight(),
contentHeight = $('#content').height();

// Not affix if sidebar taller then content (to prevent bottom jumping).
if (headerOffset + sidebarHeight < contentHeight) {
sidebarInner.affix({
offset: {
top: headerOffset - CONFIG.sidebar.offset,
bottom: footerOffset
}
});
}

setSidebarMarginTop(headerOffset).css({ 'margin-left': 'initial' });
}

function resizeListener () {
var mql = window.matchMedia('(min-width: 991px)');
mql.addListener(function(e){
if(e.matches){
recalculateAffixPosition();
}
});
}

function getHeaderOffset () {
return $('.header-inner').height() + CONFIG.sidebar.offset;
}

function getFooterOffset () {
var footerInner = $('.footer-inner'),
footerMargin = footerInner.outerHeight(true) - footerInner.outerHeight(),
footerOffset = footerInner.outerHeight(true) + footerMargin;
return footerOffset;
}

function setSidebarMarginTop (headerOffset) {
return $('#sidebar').css({ 'margin-top': headerOffset });
}

function recalculateAffixPosition () {
$(window).off('.affix');
sidebarInner.removeData('bs.affix').removeClass('affix affix-top affix-bottom');
initAffix();
}

});

修改后:

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
$(document).ready(function () {
piscesJs();
});

function piscesJs(){
initAffix();
resizeListener();
}

function initAffix () {
var sidebarInner = $('.sidebar-inner');
var headerOffset = getHeaderOffset(),
footerOffset = getFooterOffset(),
sidebarHeight = $('#sidebar').height() + NexT.utils.getSidebarb2tHeight(),
contentHeight = $('#content').height();

// Not affix if sidebar taller then content (to prevent bottom jumping).
if (headerOffset + sidebarHeight < contentHeight) {
sidebarInner.affix({
offset: {
top: headerOffset - CONFIG.sidebar.offset,
bottom: footerOffset
}
});
}

setSidebarMarginTop(headerOffset).css({ 'margin-left': 'initial' });
}

function resizeListener () {
var mql = window.matchMedia('(min-width: 991px)');
mql.addListener(function(e){
if(e.matches){
recalculateAffixPosition();
}
});
}

function getHeaderOffset () {
return $('.header-inner').height() + CONFIG.sidebar.offset;
}

function getFooterOffset () {
var footerInner = $('.footer-inner'),
footerMargin = footerInner.outerHeight(true) - footerInner.outerHeight(),
footerOffset = footerInner.outerHeight(true) + footerMargin;
return footerOffset;
}

function setSidebarMarginTop (headerOffset) {
return $('#sidebar').css({ 'margin-top': headerOffset });
}

function recalculateAffixPosition () {
$(window).off('.affix');
var sidebarInner = $('.sidebar-inner');
sidebarInner.removeData('bs.affix').removeClass('affix affix-top affix-bottom');
initAffix();
}

提取出 piscesJs() 这个能外部调用的方法。其它需要修改的如 bootstrap.js、motion.js、post-details.js、scroll-cookie.js、utils.js 等,做法都类似,这里就不一一列举了。

不明白?浏览器审查元素参考一下

在 pjax.swig 中引用抽取出来的方法,重新渲染

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
$(document).on('pjax:send', function() {
loadingBefore();
motionJs();
// piscesJs();
});

$(document).on('pjax:success', function() {
bootstrapJs();
postDetailsJs();
initAffix('473', '164'); // sidebar(scrollspy)
initCarousel();
initReadMore();
initIndexPostVisitor();
initValineAdmin();
linkCardFunc();
macPanelMan();
loadingAfter();
socialShare('.social-share');
initRating();
initCodeCopy();
initBusuanzi();
// initSidebarDimension();
// baiduAnalytics();
// baiduPush();
});

这里的 initBusuanzi(),直接是又请求了一遍

1
2
3
function initBusuanzi(){
$.getScript("https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js");
}

后期使用 revolvermaps 替换不蒜子,参考枫糖的 这篇文章

一些问题

$(“…”).lazyload is not a function

此错误一般是重复引入 JQuery 引起的冲突,仔细核查下引入 JQuery 的地方

FancyBox 2 Ajax 跨域

NEXT 5 集成的图片灯箱效果是 FancyBox 2,文档中也有 Ajax 渲染的方式

1
$(".open_ajax").fancybox({type: 'ajax'});

不过在 PJAX 后总提示跨域,首次点击图片预览时有 Bug,尝试了多种方法仍是无果,官方有说

1
Note, ajax requests are subject to the same origin policy. If fancyBox will not be able to get content type, it will try to guess based on 'href' and will quit silently if would not succeed (this is different from previous versions where 'ajax' was used as default type or an error message was displayed).

最后没办法,升级到 FancyBox 3 问题解决。utils.js 中的 wrapImageWithFancyBox 方法需要修改,用 data-fancybox 属性来渲染。下边的对比,可以看出 FancyBox 版本间变动还是挺大的,新版加了很多个性化功能。

FancyBox 2 预览:

FancyBox 2

FancyBox 3 预览:

FancyBox 3

写在最后

集成 PJAX 后,网站访问速度有了很大提升,请求数也少了很多,虽然还附带着这么多花里胡哨的东西,Who Care 呢。托管在 Github 上,没有个人服务器,这效果也算可以了。对于其它类 EJS 主题,这里只是抛砖引玉,大家可作个参考。

其它优化相关的文章:

hexo 优化与加速

点击查看

本文标题:PJAX加速站点访问

文章作者:北宸

发布时间:2020年05月01日 - 10:55:51

最后更新:2020年05月31日 - 17:20:24

原始链接:https://www.liaofuzhan.com/posts/2913572160.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------
🌞