随机图片

上篇说到文章中说到侧边栏音乐播放器,可以播放音乐,却无法实现全局音乐,即切换页面后切换文章后音乐播放器会重新加载。为了解决这个问题需引入pjax。

一、pjax

pjax是什么?

  • pjax = pushState + ajax

简单来说pjax是Ajax的升级版,即Ajax实现异步刷新,pushState 实现地质栏变更并存入历史记录。

3hbjMQ.png

可以看到本站主体由三部分,上边栏、侧边栏及中间的主体部分。要实现全局引用只需刷新主体部分即可。

这里找了两位大佬的例子:

很遗憾的是,我的博客引用上述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而是用的delegatedelegate有什么作用呢,官方定义是这样的:

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(){}
	});

至此,就能享受全局音乐了。