全局音乐 Pjax优化

上篇说到文章中说到侧边栏音乐播放器,可以播放音乐,却无法实现全局音乐,即切换页面后切换文章后音乐播放器会重新加载。为了解决这个问题需引入pjax。
一、pjax
pjax是什么?
- pjax = pushState + ajax
简单来说pjax是Ajax的升级版,即Ajax实现异步刷新,pushState 实现地质栏变更并存入历史记录。

可以看到本站主体由三部分,上边栏、侧边栏及中间的主体部分。要实现全局引用只需刷新主体部分即可。
这里找了两位大佬的例子:
很遗憾的是,我的博客引用上述pjax后,毫无反应。而且目前hugo也没有相关主题及实例。所以得亲自动手。
二、实现pjax
既然大佬的不能用,那就自己造。回归最本质的问题,从原理入手:pushState + ajax
$('a').bind('click',function(){
$.ajax({
type:'GET',
url:this.href,
success:function(data){
$('#pjax-content').html(data);//pjax-content为主体部分
}
});
window.history.pushState({url:this.href},null,this.href);
return false;
});
window.addEventListener("popstate", function() {
$.ajax({
type:'GET',
url:location.href,
success:function(data){
$('#pjax-content').html(data);
}
});
});
引入上述js后基本上能实现只刷新主体部分,但是还存在一写问题。即引入的主体部分中的链接无法实现异步刷新,但是侧边栏的都可以。开始一只找不到原因,明明绑定了a标签,但点击引入部分的链接就是无法执行上述js。最后还是参考了一下大佬 welefen 的例子才找到原因。
大佬没有用bind而是用的delegate,delegate有什么作用呢,官方定义是这样的:
delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数。
使用 delegate() 方法的事件处理程序适用于当前或未来的元素(比如由脚本创建的新元素)。
注意未来两个字。bind是只对当前页面有效,对引用的元素无效,而delegate对引入的元素也有效。
改成delegate后的代码如下:
$('body').delegate('a', 'click', function (event) {
event.preventDefault();
$.ajax({
type:'GET',
url:this.href,
success:function(data){
data = $(data).find("#pjax-content").html();
$('#pjax-content').html(data);
}
});
//改变地址栏并添加历史记录
window.history.pushState({url:this.href},null,this.href);
});
这下就完美了所有的链接都能实现异步刷新了,音乐也不随文章的改变而从新刷新了。
三、优化pjax
见了自己,得见天地了。之前大佬们的现在也差不多能看懂了。
$.pjax({
selector: 'a',
container: '#container', //内容替换的容器
show: 'fade', //展现的动画,支持默认和fade, 可以自定义动画方式,这里为自定义的function即可。
cache: true, //是否使用缓存
storage: true, //是否使用本地存储
titleSuffix: '', //标题后缀
filter: function(){},
callback: function(){}
})
welefen 大佬不愧为大佬,在实现了基本pjax的同时,还增加了:
- 页面缓存
- 过度动画
- 过滤器
- 回调函数
基本上所有要优化的点都有了。但是问题来了大佬的pjax并兼容我的需求:
- 不支持返回带html标签的代码
if ((data || '').indexOf('<html') != -1) {
pjax.options.callback && pjax.options.callback.call(pjax.options.element, {
type: 'error'
});
location.href = pjax.options.url;
return false;
}
- 只能将返回的代码放到指定的容器中,不能指定返回的容器
options = $.extend({
selector: '',
container: '', //只能指定放置的容器
callback: function () { },
filter: function () { }
}, options);
hugo的每一篇文章都是一个单独的页面,所以肯定有ajax返回的页面肯定有html标签,而且我只需要返回的主体部分,所以代码得改。
首先得增加一个参数,取返回页面的指定容器:
options = $.extend({
selector: '',
container: '',//放置的容器
_container: '',//要取的数据
callback: function () { },
filter: function () { }
}, options);
取所需数据:
if(pjax.options._container.length>0){
data = $(data).find(pjax.options._container).html();
}
最后引用改造后的js即可:
$.pjax({
selector: 'a',
container: '#pjax-content', //被替换的容器
_container: '#pjax-content', //要替换的容器
show: 'fade', //展现的动画,支持默认和fade, 可以自定义动画方式.
cache: true, //是否使用缓存
storage: true, //是否使用本地存储
titleSuffix: '', //标题后缀
filter: function(){},
callback: function(){}
});
至此,就能享受全局音乐了。