百度的无刷新搜索,并不仅仅是使用了ajax,还有它的功劳!

我们先来描述这样一个场景,我们要做一个搜索页面,这个搜索页面得满足这样的要求:
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,来体验吧。
WooDebug传送门: http://woodebug.com/account/signin 点击登录、注册按钮来切换登录注册页的时候你会发现,页面的url发生了变化,但页面没有整个的刷新。

这个站也会在后期也会使用pjax来提升体验的,现在开发阶段就不弄啦。
pjax真的是种很好的东西,强烈推荐在必要的时候使用一下。
它跟普通加载页面相比,少请求了N多个页面。
它跟普通的ajax相比,多了可改变浏览器链接,多了浏览器历史记录,少了N多的DOM操作。

缺点当然也有了,麻烦那么一丢丢,但与收益相比,很值,不然百度、阿里他们也不会在核心产品里使用到了这种技术。
追加内容 2017-01-05 07:14:14
本站已使用了pjax技术。

评论14

  • 我用的java ,普通的a链接,头部和脚,都是通过公用jsp,<%@ include file="inlayingJsp.jsp" %> 导入,每个页面都这样写了导入标签,如果改为pjax,由和区别,能做到吗?
    2016-12-15 00:11:21 回复
  • 回复@526866757:使用pjax并不关心服务器使用什么技术,因为不管使用什么技术,最后都是输出的html,然后使用这个html中的需要的部分替换当前页面的部分,就可以了。
    如果用文中提到的MoOx/pjax框架,这些替换都是框架自动替换的,比如配置了title和#content,框架就会自动从获取到html中找到title和#content来替换当前页面中的title和#content。

    当然你会发现返回的这个完整html是有点浪费流量的,因为你并不需要整个html,你只需要title和#content部分,那你就需要通过参数告诉服务器只需要返回title和#content部分就可以了,然后服务器根据要求只返回title和#content部分,但是这样就多了处理逻辑了,稍麻烦了一点。
    2016-12-15 00:26:30 查看对话 回复
  • 呆呆呆呆呆呆呆呆呆呆地
    2016-12-15 09:12:24 回复
  • 回复@ss:11
    2016-12-15 09:12:35 查看对话 回复
  • 哎哟不错喔。
    2016-12-15 16:24:58 回复
  • 回复@我喂自己袋盐: 这方法不错,值得学习!! 再问问,问答和讨论,有啥不一样??
    2016-12-15 18:47:26 查看对话 回复
  • 回复@Gipors:区别是这样的,问答是一种求助,可以采纳答案(是有状态的,未解决和已解决,现在还没做好采纳答案的功能)。
    讨论可能就是随便发个贴子讨论什么分享什么,但起名讨论貌似不太好,我也觉得好别扭,暂时也不知道叫什么好,给个建议呗。
    2016-12-15 19:35:04 查看对话 回复
  • 呀谢谢分享,当初不知道可以动态加载,没办法把所有js手动改了个遍,好气呀

    顺便问下大大,浏览器返回按钮能不能简单的使用pjax的回调呢,很早前曾见过使用pjax的大佬的页面点击浏览器的后退也是有过渡动画的
    2016-12-16 22:53:27 回复
  • 对啦我想请教下sae php 共享sql,操作完最后需要关闭sql连接吗,一直没关过,不知道这有什么作用
    蟹蟹辣
    2016-12-17 00:12:08 回复
  • 回复@qiao:后退是可以动画的,在需要加载的部分添加css就行,比如先定义好下面CSS代码:
    @-webkit-keyframes display_show{
    from{
    opacity:.6;
    transform:translateY(-15px);
    }
    to{
    opacity:1;
    transform:translateY(0);
    }
    }

    然后你在pjax加载的容器#content上加上animation:display_show 1.1s ease;就会出现display_show定义的动画啦,动画CSS如果不太了解可以百度一下。woodebug工作台中就是使用这样的方式动画的 http://woodebug.com/
    2016-12-17 12:44:32 查看对话 回复
  • 回复@qiao:sql连接一般都不需要手动关闭的,使用结束后会自动关闭的。除非你执行完sql语句后还有很耗时的执行代码,可以手动关闭一下连接释放资源。
    2016-12-17 12:52:18 查看对话 回复
  • 回复@我喂自己袋盐: soga,6翻啦,谢谢!
    2016-12-17 14:30:15 查看对话 回复
  • 文章非常好,学习了,但是使用中遇到个问题,就是文中的情况都是点击链接触发pjax的,但是实际中有时候是通过js中跳转到某个链接,这时如何触发这个pjax呢?我看了github上,没找到怎么操作。
    2016-12-25 17:54:09 回复
  • 回复@随風飞扬:啊,这个问题好,但是我也没弄过。
    思路有两条吧,
    1.使用js跳转肯定会刷新页面跳转了,把跳转的代码改成原本pjax中点击后执行的代码应该就ok了,不过如果是用框架的话,就需要改源码,貌似有点麻烦。
    2.js动态创建一个a标签,然后给这个a标签绑定pjax事件,再然后模拟点击这个a标签,这样貌似简单了点。
    2016-12-26 10:54:23 查看对话 回复
评论请先登录

最近热帖

  1. 我才是第一名 38275
  2. 谁能超过我 23778
  3. 本站源码easyQA下载地址及安装配置文档 5888
  4. 百度的无刷新搜索,并不仅仅是使用了ajax,还有它的功劳! 4140
  5. 本站用的是什么富文本编辑器呢? 3175
  6. 本站源码下载及安装配置教程 2729
  7. (● ̄(エ) ̄●) 恳请大家不要发布无意义的测试帖子吧,测试也可以发有意义的文字呀 2632
  8. 我把它改成潮流分享的社区了。。。囧 2371
  9. 关于thinkphp图片上传插件,ajax+无刷新。 2356
  10. 本站源码的开源开发进度与意见反馈 1852

近期热议

  1. 本站源码easyQA下载地址及安装配置文档 56
  2. (● ̄(エ) ̄●) 恳请大家不要发布无意义的测试帖子吧,测试也可以发有意义的文字呀 23
  3. 社区新使用了又拍云来存储图片,测试一下上传图片 18
  4. 仔细从V型注册v 18
  5. 本站源码下载及安装配置教程 17
  6. 提问与回答增加上传图片、添加代码、表情、颜表情功能 15
  7. 百度的无刷新搜索,并不仅仅是使用了ajax,还有它的功劳! 14
  8. 本站用的是什么富文本编辑器呢? 13
  9. 你这个网站的搜索框 13
  10. 本站源码的开源开发进度与意见反馈 12