百度的无刷新搜索之PJAX

我们先来描述这样一个场景,我们要做一个搜索页面,这个搜索页面得满足这样的要求:
1.为提升用户体验,必须是页面无刷新的异步请求。
2.可以将搜索结果页面链接分享给其他人。
3.搜索后可以点击浏览器的后退、前进按钮。
我们会发现使用传统的ajax技术能很好的解决第1点,却很难满足2和3。

但是百度做到了,那我们就来看看百度是怎么做的,打开百度https://www.baidu.com/ 百度一下你会发现浏览器的url是变的,但是页面却没有刷新,并且点击后退按钮也是有效的。
我们再来打开淘宝的搜索页面https://s.taobao.com 搜索后选择分类时也是url有变化,而页面却没有刷新。
那么,他们是怎么做到的呢?没错,就是标题中提到的pjax技术。

听起来高大上,其实就是在ajax的基础上增加了pushState。
pjax = pushState + ajax

pushState简单来说,就是一种可以让你在改变浏览器url和更新浏览记录的情况下而不刷新页面的东西。
知道了这个东西,我们可以大胆的想象一下淘宝搜索以后点击分类不刷新页面的窍门,我想一定是这样的:
1.当用户点击分类链接的时候,淘宝使用了js将点击事件拦截,不让你进入到你点击的页面,
2.同时向这个链接发送1次ajax请求,以获取这个链接的内容,得到内容以后展示出来就ok啦,
3.然后再做一下收尾工作,使用刚才提到的pushState改变一下浏览器url,再增加一下浏览记录,搞定。
你可能会说,听起来这么高端的pushState,会不会出现浏览器兼容性问题,问的好,解决办法也很简单粗暴,在第1步的时候不要拦截点击事件,直接进入你想进的页面就行啦,所以你完全不用担心兼容性问题。

没错,其实原理就是这么简单。

原理很简单,但实现起来却不只一种方法,讲一下最经典的两种方法吧。
1.拦截点击事件后,在发送ajax请求的时候,顺带告诉服务器,只需要页面的哪些内容,比如页首和页脚这些共用的部分就可以不用服务器返回,这样速度肯定更快一点,缺点是麻烦了一点。
2.拦截点击事件后,发送送ajax请求的时候,不告诉服务器自己需要页面的哪些内容,服务器将返回整个页面,然后可通过js得到想要的部分,优点是简单。

我是比较喜欢第2种方法的,因为实在是太简单了,服务器端真的是一行代码也不需要改,客户端嘛,Github找个框架解决,经过我的对比,我推荐一下MoOx/pjax
Github地址:https://github.com/MoOx/pjax
使用起来特别简单,在你需要添加pjax的链接上加上class="pjax"
然后使用如下语句,你的网站就支持了pjax啦
pjax_init();
//初始化pjax
function pjax_init(){
document.addEventListener('pjax:send', function() {
NProgress.start();
});
document.addEventListener('pjax:complete', function() {
NProgress.done();
});
document.addEventListener('pjax:error', function() {
});
document.addEventListener('pjax:success', function() {
});
document.addEventListener('DOMContentLoaded', function() {
var pjax = new Pjax({
elements: 'a.pjax',
selectors: [
'title',
'#content'
]
});
});
}

elements是需要进行pjax加载的链接,
selectors是需要替换的内容选择器。

细心的同学可能会发现,这里面有个叫NProgress的东西,这个东西可以让你在使用pjax加载页面的时候,页面顶部出现加载进度条.
Github传送门:https://github.com/rstacruz/nprogress

注意啦!看黑板!一个特别重要的细节!
你在a页面使用pjax打开了b页面,b页面里有加载js文件或者css文件,那么使用pjax打开这个b页面后,b页面中的js文件或者css文件是不会有效执行的,这就需要你在这个页面里动态加载一下,这里有个简单的代码可以解决这个问题:
//创建dom element,暂时只支持创建js和css
function create_element(type, url){
var head = document.head || document.getElementsByTagName('head')[0];
var element = '';
if(type == 'js'){
element = document.createElement('script');
element.type = 'text/javascript';
element.src = url;
}
else if(type == 'css'){
var element = document.createElement('link');
element.href = url;
element.rel = 'stylesheet';
element.type = 'text/css';
}
head.appendChild(element);
}

最后强调一下,使用pjax是对seo友好的,完全不影响seo。
其实我在另一个项目,任务管理工具WooDebug中已经使用了pjax,大家可以注册个账号在工作台中体验一下效果。
这个站也会在后期也会使用pjax来提升体验的,现在开发阶段就不弄啦。
pjax真的是种很好的东西,强烈推荐在必要的时候使用一下。
它跟普通加载页面相比,少请求了N多个页面。
它跟普通的ajax相比,多了可改变浏览器链接,多了浏览器历史记录,少了N多的DOM操作。

缺点当然也有了,麻烦那么一丢丢,但与收益相比,很值,不然百度、阿里他们也不会在核心产品里使用到了这种技术。
#技术# #pjax#

评论2

评论请先登录

最近热帖

  1. PPS代理节点池 69664
  2. PPS代理节点池② 26710
  3. 订阅池记录 8023
  4. 基于 Harbor 搭建 Docker 私有镜像仓库 6463
  5. V2ray免费账号 2358
  6. PPS代理节点池③ 2202
  7. 全栈开发笔记 1665
  8. 百度的无刷新搜索之PJAX 1573
  9. css之rem布局(rem.js) 1492
  10. docker swarm 集群高可用 1308

近期热议

  1. GITHUB项目 55
  2. PPS代理节点池 50
  3. WEB代理地址 43
  4. 全栈开发笔记 42
  5. ROBOT机器人之路 31
  6. C++回归之路 19
  7. OCR识别探索 16
  8. PPS代理节点池② 14
  9. DB到ES同步之路 11
  10. 接码平台地址 9