若是最近打電話給武漢的小夥伴,他說信號很差,那麼相信我,他確定不是真的信號很差,也不是不想和你說話,而是他可能在冰箱裏。。。武漢的天氣歷來都是喜怒無常的,是吧,屌絲氣十足,今年也是絲毫看不出有任何逆襲的跡象和可能性,固然咱也不必去操那個心;好吧,其實你把他看做是我也是能夠的;不要聯想,趕快進入正題;前端
JS能一路從小丑變爲白天鵝,跟ajax技術的風靡有莫大的關係,伴隨H五、ES六、Nodejs的發展與普及,不斷將前端推向新的高度,現在JS的地位如日中天啊!node
用過backbone、Angular、React這些框架的確定對前端路由都不陌生,而他們基本上都是經過監聽hash的變更來更新和切換視圖的,固然React還支持browserHistory,也就是pjax的重點pushState,屬於H5的範疇,除了BSIE,兼容性就很少說了;pjax=pushState+ajax,ajax都不陌生,那麼揭開pjax的神祕面紗,搞懂pushState就是咯,恩,爲了保持信心,先這麼認爲吧;jquery
若是仍是不太清楚pjax究竟是作什麼的,那麼只好這麼說了:改變URL(不是hash),局部刷新(ajax);ajax
若是依然不太明白,那隻多是由於思惟定式了,對於前端來講,通常都知道改變URL(不是hash),頁面必定會刷新的,而pushState就是要讓你知道,No!改變URL也能夠只刷新局部!json
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緩存app
雖說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