ajax只能局部刷新吗,Ajax真的只能用来局部刷新吗?

pjax-cover.png

端午六一休息三天宅了一天, 独自去市中心里转了一天, 就剩下一天了 [惊恐]. 压根就没有马上要考试了的感觉嘛! 文章也是好久没更新了, 浑浑噩噩过下去曾的好嘛>.O. 好嘛, 那就来写点干货好了, 也是最近在搞 Ghost, 把这个主题的逻辑 (原先是 jQ ) 用原生 js 重写了一遍 (还顺便搞了个小项目 GhostBot 来处理站内搜索), 总结总结研究出了些什么好了, 废话讲得多, 直接进正题吧.

##PJAX

关于题目抛出的这个问题, 我既然都这么问了, 正常人都知道答案肯定是不是咯. 其实 AJAX 这个东西一直以来都是被当做只能处理小范围的, 异步的页面更新, 它的优点就在于可以实现页面的无刷新操作. 但是这也会造成一些问题, 比如对搜索引擎兼容性不好啦 (抓不到 ajax 载入的信息), 还有无法后退神马的!

对于无法前进后退, 邪恶的 W3C 就在 HTML5 中搞了一个叫history对象的东西, 使用 history 对象的pushState方法给浏览器的浏览历史中塞入一个地址, 返回的时候再借助popstate事件来还原到原先的模样, 这样一来 AJAX 和 pushState 就开始名正言顺地搞基了! 于是我们就把这俩基友称为PJAX.

##(正常情况下) 它是如何工作的

这个东西其实不是什么新生事物, 国内在 2012 年就已经对它有一些提及, 只是没有流行开而已, 经常上 GitHub 和 Youtube 的人不知道有没有发现这俩其实早就使用PJAX了.

HTML5 新增的方法在这里:

history.pushState(state, title [, url]) : 向历史记录 (把它看做一个栈) 的顶端加入一条记录, state 是一个指明状态的对象, 如 {url: 'xxxxx', title: 'yyyyy', myInfo: 'zzzzz'};

history.replaceState(state, title [, url]) : 跟上面差不多, 功能就是替换历史记录顶上的记录;

1

2

3

4

5

window.history.pushState({

title: 'Home Page',

url: 'http://balabala.com'

}, document.title, location.href);

响应前进后退的事件:

window.onpopstate : 上面传递的 state 对象会成为 event 的子对象,这样就可以拿到存储的 title 和 URL 了. 这个事件在我所测试的 Chrome 36dev 和 Safari 7 中表现有差异, 具体在页面首次载入时, Chrome 不会触发这一事件而 Safari 会触发.

1

2

3

4

5

6

window.onpopstate = function (ev) {

var state = ev.state;

if (state) {

//do ajax here;

}

}

国内也早就有很多开源的 PJAX 插件, 基于 jQuery, qwrap, kissy 什么的, 但是貌似我没有找到原生的啊, 反正到最后还是自己写了个渣渣的.

### 前端处理

首选我们需要一个容器 (container) 来做页面中需要改变的部分. 然后将不需要改变的部分, 比如 footer, header 放在容器的外面.

1

2

3

4

5

<>

#container{height:100%;width:100%;}

>

{{#content}}

对于页面上所有的超链接 (a 标签), 我们都需要采取 hijack(劫持) 的方式来处理点击事件.

1

2

3

4

5

6

7

8

9

var a = document.getElementsByTagName('a');

Array.prototype.slice.call(a).forEach(function (_a){

_a.onclick = hijackLinks; //hijackLinks为链接处理函数

});

function hijackLinks (ev){

if(/* 外域链接 */) return;

ev.preventDefault();

// 处理PJAX

}

差异于一般的 AJAX 返回 JSON, PJAX 的后端返回的一般是 HTML 片段. 前台再直接使用 innerHTML 来完成页面无刷. 对于同一个 URL, 如何告诉后端这是一个 PJAX 请求呢? So easy! 直接在 HTTP 请求头上带上标记就好了. 在前端 Ajax 中带上

1

setRequestHeader(‘PJAX’, ‘true’);

### 后端处理

接上面的话, 直接在后台判断 HTTP 头就行了 (以 PHP 为例):

1

2

3

4

5

6

if(array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true'){

//在这里输出你的 HTML 片段

}else{

//正常输出

}

## 为什么要用它呢

简而言之, PJAX = AJAX + history.pushState. 这货不仅可以无刷新地改变页面内容, 还可以改变 URL 和浏览器历史记录, 使得前进后退的体验一体化.

Wow, 不明觉厉的样子也.

好吧, 那我们上个图来看看, 以 GitHub 为例.

如下图, 我首先打开了一个 (我的 0.0) GitHub 主页, 可以看到浏览器的历史记录是空的 (灰色);

pjax-before.png

然后我点击了 Contributions 按钮. 页面改变了, 但是页面并没有刷新, 看样子是 PJAX 基佬起作用了! 浏览器的历史记录里面出现了刚才访问的位置, 地址栏也变化了, 下面的调试窗口显示有三条 XHR (XMLHttpRequest) 请求成功.

pjax-after.png

还是不明白? 自己去 GitHub.com 看个究竟把!

噢对了, 还没说为什么要用 PJAX 呢.

无刷新, 速度快 (快就是王道)

无刷新意味着可以在页面改变的时候施展各种绚丽的动画 (漂漂的, 暖暖的)

对搜索引擎支持好, 有利于 SEO

我™就是喜欢它怎么着, 打我呀

顺便说说弊端.

逻辑比较复杂. (跟正常方式不一样的都叫复杂)

需要前后台配合. (这点后面再讲, 其实可以克服)

跨域限制. (其实这是安全原则, 也可以不算弊端拉)

兼容性什么就不提了, 不用优雅的 Chrome 的都别来我的 blog 就对了.

## 我的方案 (不正常情况)

本站就使用了全站内链的 PJAX 无刷, 并开启了 10 分钟的 localStorage, 以尽量减少 HTTP 请求.

因为 Ghost 的主题只是提供了 hbs 模板文件和静态资源文件, 我并不能通过修改 Ghost 内核的方式来使得输出 HTML 片段. 所以只能通过解析 html 的方式来进行 (电脑牛逼, 不怕卡, 打我呀).

1

2

3

4

5

6

7

8

var ajax = new Ajax(); //我封装的一个Ajax类

ajax.get(url, function (doc) {

var _html = document.createElement('html');

_html.innerHTML = doc; //不用append到文章中即可在内存中解析HTML

var newContainer = _html.querySelector('#container');

document.querySelector('#container').innerHTML = newContainer.innerHTML;

//do others.

});

这样就减少了一个弊端, 就是可以不修改后台直接在前台做好所有的工作.

## 兼容性

直接看图吧

pjax-jrx.png

IE10+

Chrome 5+

Safari 5+

Opera 11.5+

Firefox 4+

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值