前言
折腾typecho也有好一段时间了,没什么好写的就干脆水篇教程(x
虽然给typecho用上pjax技术的文章也有很多大佬也写过了,不过我还是想写下自己使用的jquery-pjax的一些内容和经验
项目地址jquery-pjax
正文
引入资源
先在页面中引入jQuery和jquery-pjax
<script src="path/to/jquery.js"></script>
<script src="path/to/jquery.pjax.js"></script>
注意引入的jQuery的版本,推荐用2.0.1或更高,我使用的jQuery为3.3.1版本,jquery-pjax为2.0.1版本
你的所有pjax相关代码都应在引入jquery-pjax.js
的script
标签之后
基本使用
$(document).pjax(selector, [container], options)
- selector:需要绑定的点击事件的元素的选择器
- container:唯一pjax容器的选择器。
- options:
选项 | 默认值 | 说明 |
---|---|---|
timeout | 650 | ajax超时时间(毫秒),超时后强制刷新整个页面 |
push | true | 使用pushState在浏览器中添加历史记录 |
replace | false | 替换URL地址但不添加浏览器历史记录 |
maxCacheLength | 20 | 容器元素缓存内容的最大值(次) |
version | string 或function ,返回当前pjax版本 | |
scrollTo | 0 | 浏览器滚动条的垂直滚动位置。设为false 时禁止滚动 |
type | "GET" | 参考 $.ajax |
dataType | "html" | 参考 $.ajax |
container | 被替换内容元素的CSS选择器 | |
url | link.href | string 或function ,返回ajax请求响应的URL |
target | link | pjax 事件 中relatedTarget 属性的最终值 |
fragment | css选择器,提取ajax响应内容中指定的内容片段 |
我的代码:
$(document).pjax(
'a[href^="' + THEME_CONFIG.SITE_URL + '"]:not(a[target="_blank"], [no-pjax],a[rel~="nofollow"])',
{
container: '#pjax-container',
fragment: '#pjax-container',
timeout: 8000
})
其中THEME_CONFIG.SITE_URL
是站点的URL地址,选择器的详细用法可以参考jQuery 参考手册 - 选择器
send
和complete
事件
pjax提供了两个事件可以使得我们可以在刷新局部内容的时候显示一些过渡动画,比如我现在用的NProgress
事件 | 参数 | 说明 |
---|---|---|
pjax:send | xhr, options | pjax通过链接点击已经开始之后触发 |
pjax:complete | xhr, textStatus, options | 无论结果如何,都在ajax响应完成后触发 |
示例代码:
$(document).on('pjax:send', function () {
NProgress.start();
}).on('pjax:complete', function () {
NProgress.done();
});
你当然可以使用别的过渡动画
一些JS的重载
pjax在每次请求数据的时候只会获取你所设置的容器内的数据,所以必须在pjax结束之后回调函数里重新加载一些特定的js函数。
我的代码:(已简化一些判断和稍作修改使得容易阅读)
//#header和#body的动画
$('#header').removeClass('slideOutUp').addClass('slideInDown');
$('#body').removeClass('fadeOut').addClass('fadeIn');
fancybox(); //图片灯箱效果
hitokoto(); //一言的重新获取
lazyload(); //图片懒加载
hljs.init(); //highlight.js代码高亮
commentPlus.init(); //评论的一些增强功能,比如表情
postOther.init(); //文章内一些增强功能
closeNav(); //关闭导航栏
/** 重载部分统计代码 来自QQ爹博客*/
/** baidu */
if (typeof _hmt !== 'undefined') {
_hmt.push(['_trackPageview', location.pathname + location.search]);
}
/** google */
if (typeof ga !== 'undefined') {
ga('send', 'pageview', location.pathname + location.search);
}
重载代码是根据自己的实际情况进行编写的,不同的情况的代码一般不一样,上面只是给出了一个例子
完整代码
以下是我的博客使用的pjax的完整代码,为方便阅读和参考已做部分修改
var doPjaxStartAction = function () {
$("#header").toggleClass('slideOutUp');
$("#body").toggleClass('fadeOut');
$("#wrapper").hide();
}
var doPjaxCompleteAction = function () {
('#header').removeClass('slideOutUp').addClass('slideInDown');
$('#body').removeClass('fadeOut').addClass('fadeIn');
fancybox(); //图片灯箱效果
hitokoto(); //一言的重新获取
lazyload(); //图片懒加载
hljs.init(); //highlight.js代码高亮
commentPlus.init(); //评论的一些增强功能,比如表情
postOther.init(); //文章内一些增强功能
closeNav(); //关闭导航栏
/** 重载部分统计代码 来自QQ爹博客*/
/** baidu */
if (typeof _hmt !== 'undefined') {
_hmt.push(['_trackPageview', location.pathname + location.search]);
}
/** google */
if (typeof ga !== 'undefined') {
ga('send', 'pageview', location.pathname + location.search);
}
}
$(document).pjax('a[href^="' + THEME_CONFIG.SITE_URL + '"]:not(a[target="_blank"], [no-pjax],a[rel~="nofollow"])',
{
container: '#pjax-container',
fragment: '#pjax-container',
timeout: 8000
}).on('pjax:send', function () {
NProgress.start();
doPjaxStartAction();
}).on('pjax:complete', function () {
NProgress.done();
doPjaxCompleteAction();
})
解决评论无法回复
在/var/Widget/Archive.php
文件1720行至1792行左右可以看到如下评论回复的相关的js代码
$header .= "<script type=\"text/javascript\">
(function () {
window.TypechoComment = {
dom : function (id) {
return document.getElementById(id);
},
create : function (tag, attr) {
var el = document.createElement(tag);
for (var key in attr) {
el.setAttribute(key, attr[key]);
}
return el;
},
reply : function (cid, coid) {
var comment = this.dom(cid), parent = comment.parentNode,
response = this.dom('" . $this->respondId . "'), input = this.dom('comment-parent'),
form = 'form' == response.tagName ? response : response.getElementsByTagName('form')[0],
textarea = response.getElementsByTagName('textarea')[0];
if (null == input) {
input = this.create('input', {
'type' : 'hidden',
'name' : 'parent',
'id' : 'comment-parent'
});
form.appendChild(input);
}
input.setAttribute('value', coid);
if (null == this.dom('comment-form-place-holder')) {
var holder = this.create('div', {
'id' : 'comment-form-place-holder'
});
response.parentNode.insertBefore(holder, response);
}
comment.appendChild(response);
this.dom('cancel-comment-reply-link').style.display = '';
if (null != textarea && 'text' == textarea.name) {
textarea.focus();
}
return false;
},
cancelReply : function () {
var response = this.dom('{$this->respondId}'),
holder = this.dom('comment-form-place-holder'), input = this.dom('comment-parent');
if (null != input) {
input.parentNode.removeChild(input);
}
if (null == holder) {
return true;
}
this.dom('cancel-comment-reply-link').style.display = 'none';
holder.parentNode.insertBefore(response, holder);
return false;
}
};
})();
</script>
";
注意在1739行和1774行:
$this->respondId
不能回复是因为respondId输出不对,因为在pjax获取另一个页面的时候这个ID没有被修改过来。
所以比较简单的方法是将上面那段代码插入到comments.php
文件中(同时也在pjax的容器内),这样每次pjax进入不同的文章时,这个ID就会正确输出。
其他
开启pjax需要将设置->评论->开启反垃圾保护
的勾选取消。这里推荐一个反垃圾评论的插件SmartSpam
。
后记
除了jquery-pjax,这里再推荐一个pjax的项目MoOx/pjax。
与前者相比,后者的部分优点在于
- 不仅限于一个容器
- 不依赖于jQuery且体积特别小
这个pjax项目也是我之前用的,后来还是换成了现在的这个。
当然比较有名的还有Instantclick
By wos at 2020-8-25 01:07 am.
大佬你的文章阅读量好高呀,我是从谷歌搜索到这篇文章の,您是怎么优化SEO的
By lkk呀小木匠 at 2020-2-12 08:43 am.
@lkk呀小木匠
(/ω\) 毫无优化(真的)我也不知道怎么就收录了
By Siphils at 2020-4-2 09:54 pm.
大佬加我QQ2825626780
By 金金多歪 at 2020-1-28 06:37 pm.
我不知道我弄得对不对,我把jQuery和jquery-pjax引入然后引入最后的引入你写好的完整代码,应为我想我用的主题和你一样。应该是可以了,但是我安装了个插件播放音乐的怎么让他不刷新呢?
By 金金多歪 at 2020-1-28 04:48 pm.
我不知道我弄得对不对,我把jQuery和jquery-pjax引入然后引入最后的引入你写好的完整代码,应为我想我用的主题和你一样。应该是可以了,但是我安装了个插件播放音乐的怎么让他不刷新呢?
By 金金多歪 at 2020-1-28 04:48 pm.
@金金多歪
你要重载的是你的插件,要先找到你的播放器的载入代码,而不应该完全照搬我的代码
By Siphils at 2020-4-2 09:52 pm.
By 云武 at 2019-8-26 03:23 pm.
从老哥这里学到了很多
可能是老哥手速太快,打错了些地方吧,纠正一下下
1.[解决评论无法回复]的地方呢,第一行$header哪里多了一个“.”
2.还是[解决评论无法回复]的那段代码,光是插入可能不够,还要输出一下,不然还是无法刷新。
By 季悠然 at 2019-6-29 03:05 pm.
@季悠然
我看了下,代码没错哦。因为$header之前也有使用,这里用的是英文句号连接符。
第二个问题的话,应该是我文章表达的不够清楚的问题,我说的插入指的是把那一段代码复制粘贴到主题的pjax容器内。
By Siphils at 2019-6-29 05:06 pm.
@Siphils
学业不精,打扰了
By 季悠然 at 2019-6-29 06:37 pm.
@季悠然
By Siphils at 2019-6-29 11:05 pm.
请问fancybox();函数的具体实现。
By zayu at 2019-3-9 07:55 pm.
@zayu
https://fancyapps.com/fancybox/3/ 用的是别人的项目
By Siphils at 2019-3-9 09:35 pm.
@Siphils
了解了,开始用的fancybox2,pjax局部刷新后咋都回调不回去。。。。
By zayu at 2019-3-9 09:36 pm.
前几天我正好用到Pjax, 发现pjax版本和jquery版本之间有着微妙的联系.
By Hoe at 2018-11-23 10:21 am.
@Hoe
是的 jquery-pjax要注意jquery的版本
By Siphils at 2018-11-23 01:51 pm.
早点有这篇文章就好了……我自己琢磨了好久呢
另外代码框样式真好看,我在 Mashiro 那边看到过相似的,咋弄的啊
By 熊猫小A at 2018-10-14 11:48 am.
@熊猫小A
By Siphils at 2018-10-14 12:38 pm.