一、前言

web发展经历了一个漫长的周期,最开始很多人认为Javascript这们语言是前端开发的累赘,是个鸡肋,那个时候人们还享受着从一个a链接蹦到另一个页面的web神奇魔术。后来随着JavaScript的不断更新换代,他的功能不仅仅是为网页添加一点特效了,语言本身的加强以及对DOM操作能力的提升让他在前端大放光彩。尤其是ajax的出现,让JavaScript以及整个web的发展翻开了崭新的一页。

利用ajax局部刷新页面,相信很多人玩得相当熟练了。如果整个页面的刷新都是使用ajax,我们可以称之为一个webapp,所有的逻辑都是在当页处理,这种形式的页面带来的体验是十分不错的,减少了那些比较“冗余”的页面跳转、新开页面等。不过,webapp的代码是十分不好维护的,页面逻辑太多太深,出点小问题,整个页面就会瘫痪,而且不方便定位bug,可维护性很低。

二、PJAX的实现与应用

1.场景再现-ajax弊端

ajax是一个非常好玩的小东西,不过用起来也会存在一些问题。

我们可以利用ajax进行无刷新改变文档内容,但是没办法去修改URL,有童鞋要问,这里为什么一定要修改URL呢?一个URL代表一个特定的网络资源,ajax修改了页面的内容,所以用不同的URL去标识他们,这个还是挺有必要的。

比如我们设计了一个单词查询的页面,比较合理的UR应该是http://example.com/word,不同的word对应不同的内容,但是如果整个页面都是ajax实现,我们就没法去修改/word了,当然我们可以使用hash如http://example.com#word,但这样就不能很好的处理浏览器的前进和后退问题。如:在页面中查询了单词A的翻译,接着又查询了单词B,这个时候浏览器的浏览历史会生成http://example.com#A和http://example.com#B两个记录,可是当我们从B转回A的时候,AJAX的效果还停留在B的状态(页面显示的还是单词B的翻译)。部分浏览器对此问题引入了onhashchange的接口,只要URL的hash值发生变化,我们的程序就可以监听并做出相应。不过对于那些木有这个接口的浏览器,就得定时去判断hash的变化了。

而这样的方式对搜索引擎是十分不友好的,twitter和google约定使用hash bang (#!xxx),也就是hash后面的第一个字符为感叹号,这样的网址他们是会爬取的,但是其他搜索引擎不支持。PJAX可以在改变页面内容的同时也改变他的URL,下面来说说PJAX和他的应用。

2.什么是PJAX

history API中有几个新特性,分别是history.pushState和history.replaceState,我们把pushState+AJAX进行封装,合起来简单点叫,就是PJAX~ 虽说实现技术上没什么新东西,但是概念上还是有所不同的。

PJAX的基本思路是,用户点击一个链接,通过ajax更新页面变化的部分,然后使用HTML5的pushState修改浏览器的URL地址,这样有效地避免了整个页面的重新加载。如果浏览器不支持history的两个新API或者JS被禁用了,那这个链接就只能跳转并重新刷新整个页面了。和传统的ajax设计稍微不同,ajax通常是从后台获取JSON数据,然后由前端解析渲染,而PJAX请求的是一个在服务器上生成好的HTML碎片,如下图所示:

客户端向服务器发送一个普通的请求(1),其实也就是点击了一个链接,服务器会相应这个请求(2),返回一个html文档。客户端向服务器发送一个有PJAX标志的请求(3),此时服务器只返回一个html碎片(4)。但是这两次请求都让客户端的URL变化了,希望上面的说明可以让你明白了PAJX和AJAX的区别了。

3.PJAX的实现

先看一个小DEMO吧,这个DEMO也写了我半个多小时,看之前先说明一下,打开你的现代浏览器(chrome,Firefox,opera,IE9+等),进入gallery页面,查看图片的时候注意观察浏览器的title和url变化,点击前进后退按钮也注意查看其变化。我已经在浏览历史管理中push了三条历史记录。

DEMO地址:http://qianduannotes.duapp.com/demo/PJAX/index.html

如果你还没有理解上面说的PJAX和AJAX的区别,看完这个demo,你应该有所领悟吧!在URL变化之后,页面并没有刷新,而是继续完成自己的动画(demo中为fadeOut)。

在HTML4,Histroy对象有下面属性方法:

  • length:历史堆栈中的记录数。
  • back():返回上一页。
  • forward():前进到下一页。
  • go([delta]):delta是个数字,如果不写或为0,则刷新本页;如果为正数,则前进到相应数目的页面;若为负数,则后退到相应数目的页面。

在HTML5中,新增了两个方法:

  • pushState(data, title [, url]):往历史堆栈的顶部添加一条记录。data为一个对象或null,它会在触发window的popstate事件(window.onpopstate)时,作为参数的state属性传递过去;title为页面的标题,但当前所有浏览器都忽略这个参数;url为页面的URL,不写则为当前页。
  • replaceState(data, title [, url]):更改当前页面的历史记录。参数同上。这种更改并不会去访问该URL。

当点击“上一张”、“下一张”这两个链接的时候,首先通过pushState修改URL以及修改document.title,那这个时候你就可以当做文档已经进入了另外一个链接了,然后该干什么干什么。demo中是让图片fadeOut,fadeOut完了之后让浏览器去加载资源,这个步骤就是正常的AJAX操作啦,没有什么特殊之处了~

因为只准备了三张图片,所有后台写的也比较简单:

<?php
error_reporting(false); $num = $_GET['num']; if(array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true'){
if($num == 1) {
?>
<div class="imgwrap">
<img src="./images/1.jpg" />
</div>
<span><a href="num=2" class="next">下一张&gt;&gt;</a></span>
<?php
} else if ($num == 2) {
?>
<div class="imgwrap">
<img src="./images/2.jpg" />
</div>
<span><a href="num=1" class="previous">&lt;&lt;上一张</a>
<a href="num=3" class="next">下一张&gt;&gt;</a></span>
<?php
} else {
?>
<div class="imgwrap">
<img src="./images/3.jpg" />
</div>
<span><a href="num=2" class="previous">&lt;&lt;上一张</a></span>
<?php
}
}
?>

上面那张图中,我们看到了,并不是每个连接都使用PJAX来加载,如果有X_PJAX标识,我们才会添加相应的处理。js中稍加注意可以看到:

$.ajax({
"url": "./interface.php",
"data": {
"num": num
},
"dataType": "html",
"headers": {
"X_PJAX": true
}
});

请求中:

Accept:text/html, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Connection:keep-alive
Host:qianduannotes.duapp.com
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
X-Requested-With:XMLHttpRequest
X_PJAX:true

我在请求的header中加了一个X_PJAX的头,而后台在处理的时候也做了判断:

function is_pjax(){
return array_key_exists('HTTP_X_PJAX', $_SERVER)
&& $_SERVER['HTTP_X_PJAX'] === 'true';
}

并不是一定要求在header头部中加入X_PJAX的信息,你也可以在url中加入相关的参数,比如:http://example.com?pjax=1,或者其他方式,只要前后端达到一个共识就行。

三、开源的PJAX库

已经有人对这个东西做了封装,我就不重复造轮子了。

并不是页面中所有的链接都需要使用PJAX加载,所有在需要这个东西的a标签上加一个属性,如data-pjax=true,然后统一添加事件。

四、注意事项

  1. 如果浏览器不支持pushState接口函数,那就只能退化为ajax或者使用hash bang了~
  2. 本地环境下使用的话,浏览器会报错:`Uncaught SecurityError: A history state object with URL file:///E:/baidu_app/demo/PJAX/pic-2' cannot be created in a document with origin 'null'. ,所以如果你要测试的话,请把代码丢到服务器上!
  3. 为了得到更好的体验,PJAX经常配合localStorage来使用,把请求到的内容缓存到本地,再一次请求的时候先从本地查看。如果你的内容是动态变化的,缓存的时候加一个缓存时间,方便更新缓存。
  4. 还有一个容易忽略的东西是统计,使用PJAX只会局部刷新页面,如果忽略了对统计函数的更新,那就会让你失去很多数据。

五、参考资料

(转)PJAX的实现与应用的更多相关文章

  1. PJAX的实现与应用

    一.前言 web发展经历了一个漫长的周期,最开始很多人认为Javascript这们语言是前端开发的累赘,是个鸡肋,那个时候人们还享受着从一个a链接蹦 到另一个页面的web神奇魔术.后来随着JavaSc ...

  2. 有人要分享pjax吗?

    安装 1.在 composer.json 的 require里 加入 "yuanchao/pjax-for-laravel-5": "dev-master" 2 ...

  3. PJAX初体验(主要是利用HTML5 新增API pushState和replaceState+AJAX)

    说在前面 什么是PJAX呢? 站在应用角度的就是既实现了页面无刷新的效果,同时也产生了浏览器的前进和后退,而且url也会变化. 也不是什么新鲜技术,主要是AJAX+html5 pushState和re ...

  4. Pjax调用

    $.pjax({container:'#content_center',url:href,data:data}); $(document).on('pjax:send', function() {// ...

  5. pjax技术的应用

    一.什么是PJAX? 现在有一些网站(apicloud,  github)支持这样一种浏览方式,当你点击站内的一个连接的时候,不是传统的跳转到另外一个连接,而是类似ajax的局部刷新改变页面内容,但是 ...

  6. yii2 pjax使用

    Pjax::begin(['id'=>'datalist']); echo GridView::widget([ 'dataProvider' => $dataProvider, 'col ...

  7. jQuery Pjax – 页面无刷新加载,优化用户体验

    pjax 是 HTML5 pushState 以及 Ajax 两项技术的简称,综合这两个技术可以实现在不刷新页面的情况下载入 HTML 到当前网页,带给你超快速的浏览器体验,而且有固定链接.标题以及后 ...

  8. 从零开始,做一个NodeJS博客(四):服务器渲染页面与Pjax

    标签: NodeJS 0 一个星期没更新了 = = 一直在忙着重构代码,以及解决重构后出现的各种bug 现在CSS也有一点了,是时候把遇到的各种坑盘点一下了 1 听歌排行 API 修复与重构 1.1 ...

  9. yii2 Pjax的使用

    有两个例子:刷新时间和数据显示排序 1.刷新时间 (1)控制器中的方法:Time public function actionTime() { return $this->render('tim ...

  10. jquery.pjax.js bug问题解决集锦

    jquery.pjax 是一个很好的局部刷新插件,但实际应用过程是还是会有很多小问题,部分问题解决如下: 1.pjax 局部加载时候,IE 存在缓存问题,很容易理解,pjax是通过jquery的aja ...

随机推荐

  1. everyday two problems / 3.11 - 3.17

    7日共14题,因为3.14两题相同,所以实际总共13题 13道题分为难易两部分,没有按照时间顺序排列题目 A.易: 1.覆盖数字的数量 题意: 给出一段从A - B的区间S(A,B为整数) 这段区间内 ...

  2. Leetcode 49.字母异位词分组

    字母异位词分组 给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. 示例: 输入: ["eat", "tea", " ...

  3. Master Nginx(7) - Nginx for the Developer

    Caching integration No application caching Caching in the database Caching in the filesystem Changin ...

  4. Lifting the Stone 计算几何 多边形求重心

    Problem Description There are many secret openings in the floor which are covered by a big heavy sto ...

  5. AngularJS:实现轮播图效果

    实现步骤如下: 要实现这个功能,可以http://angular-ui.github.io/bootstrap/ 中的控件实现.实现步骤如下: 1. 下载ui-bootstrap.js程序http:/ ...

  6. ListView的基本使用技巧

    ListView的基本使用技巧 1.headerView和footerView 2.ViewHolder 3.OnScrollListener 4.单行刷新 5.其它细节 ListView提供head ...

  7. 翻翻git之---自己定义邮件发送buttonSendButton(流程分析,实现思路能够学习下)

    转载请注明出处:王亟亟的大牛之路 距离过春节还有1天.继续这一系列的git翻料之旅. 昨天的工具类真的非常棒,这里再推崇一下 传送门:http://blog.csdn.net/ddwhan0123/a ...

  8. 使用Pods和自定义静态库实现多工程联编

    使用Pods和自定义静态库实现多工程联编 字数607 阅读112 评论0 喜欢0 近来随着公司项目开发的深入,项目的规范也就越来越高了,为了更加方便的管理自定义静态库与pods之间的联系,好好的研究了 ...

  9. @Component注解

    @component (把普通pojo实例化到spring容器中,相当于配置文件中的 <bean id="  " class="   "/>)泛指各 ...

  10. Advapi32.dll 函数接口说明

    Advapi32.dll 函数接口说明             函数原型                               说明    AbortSystemShutDown         ...