pjax不再神秘,hash、state那点事

初步理解

如果最近打电话给武汉的小伙伴,他说信号不好,那么相信我,他肯定不是真的信号不好,也不是不想和你说话,而是他可能在冰箱里。。。武汉的天气从来都是喜怒无常的,是吧,屌丝气十足,今年也是丝毫看不出有任何逆袭的迹象和可能性,当然咱也没必要去操那个心;好吧,其实你把他看作是我也是可以的;不要联想,赶快进入正题;

JS能一路从小丑变为白天鹅,跟ajax技术的风靡有莫大的关系,伴随H5、ES6、Nodejs的发展与普及,不断将前端推向新的高度,如今JS的地位如日中天啊!

用过backbone、Angular、React这些框架的肯定对前端路由都不陌生,而他们基本上都是通过监听hash的变动来更新和切换视图的,当然React还支持browserHistory,也就是pjax的重点pushState,属于H5的范畴,除了BSIE,兼容性就不多说了;pjax=pushState+ajax,ajax都不陌生,那么揭开pjax的神秘面纱,搞懂pushState就是咯,恩,为了保持信心,先这么认为吧;

如果还是不太清楚pjax到底是做什么的,那么只好这么说了:改变URL(不是hash),局部刷新(ajax);

如果依然不太明白,那只可能是因为思维定式了,对于前端来说,一般都知道改变URL(不是hash),页面一定会刷新的,而pushState就是要让你知道,No!改变URL也可以只刷新局部!

基本实现

1. HTML5 API

实现pjax其实并不难,比如jquery.pjax.js,已有现成的API供你直接使用;只是最近无意中发现国内有几个站点已经开始使用pjax技术了,页面体验非常好;而我刚入门React,不想搭着Jquery一起用,只好自己造个ajax的轮子用着,然后自然就想到了这个轮子应该包含pjax;然后发现自己太年轻了,当然有想法是好的;

实现pjax主要要用到H5 history的几个API:pushState(data,str,url),replaceState(data,str,url),onpopstate事件;onpopstate会在用户点击浏览器上的前进后退或者程序的history.go(s)触发,这时history.state的值即对应为pushState中data的值,这样看来,data是可以缓存ajax拉取过来的数据的,不过别高兴的太早,它有大小限制的——640K;反正都是H5,localStorage够用吧!

2. localStorage缓存

虽然说Redux起初挺不好理解的,不过说真的,这套做法还是非常不错的,比如,可以借鉴Redux的状态容器机制,咱也构造一个容器保存所有pushState时的数据,以URL为参考,同时用localStorage缓存起来,如果非要将localStorage的存储时间加个期限,我想可以参考:《localStorage也可以限时保存登录信息》;action就是判断是否支持pushState,取消a链接的默认跳转等pjax转化操作;reducer就是先判断该链接地址对应的缓存是否存在来决定是否由ajax GET请求该a链接对应的href,将返回的数据用localStorage保存或更新;dispatch(action)即将数据填充到对应containor;自己实现当然显麻烦,好吧,还是用jquery.pjax.js吧;

3. 真实面目

pushState会向浏览器历史记录写入一条记录,同时用传入的url替换当前浏览器上的URL,那么pjax其实就是掩人耳目、花拳绣腿的改个URL,最终还是ajax了,是吗?如果你也这么想,那么你真的是天真又可爱,因为对前端而言,咱要做的就是掩人耳目式的修改个URL,然后局部刷新;

4. 服务端改造

既然是掩人耳目式的修改URL,那么如何面对主动刷新后404的现实呢?所以前面说了,要保持信心;当然接下来要做的是后端的事,暂且将pjax的请求统一为与页面刷新时一样的GET请求吧(具体请求方式需前后端协商),前端在pjax请求上加个标记让后端知道该次为pjax请求只需返回一个片段或json,这个标记可以是setHeader或请求参数里加个pjax=1之类的,后端判断这个标记来确定返回一个完整页面还是返回局部内容或局部内容的数据json,这样就可确保pjax后的URL刷新后不是404;

//pjax请求带pjax header
$.ajax({
    url:a.attr('href')ajaxUrl,
    type:'GET',
    headers:{pjax:true},
    success:function(data){
        //localStorage ...
        history.pushState('','',url);
        //containor 填充
    }
});
//Nodejs
app.get(path,function(req,res,next){
    var pjax=req.headers['pjax'];
    if(pjax){
        //...
        res.json({
            data:page_content
        });
    }else{
        //...
        res.send(page);
    }
});

这样看来,其实并没有想象那么复杂,我想,不是对IE789有特别要求的,都可以考虑使用,为了兼容也可以先判断是否支持pushState,决定是否将链接转化为pjax;这种事前端做的太多了,何乐而不为呢?

就这兼容性。。。。。。你 si bu si sa

原文来自:花满楼(http://www.famanoder.com/boke...

展开阅读全文

没有更多推荐了,返回首页