我们先来描述这样一个场景,我们要做一个搜索页面,这个搜索页面得满足这样的要求:
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#