一、前言web發(fā)展經(jīng)歷了一個(gè)漫長(zhǎng)的周期,最開始很多人認(rèn)為Javascript這們語(yǔ)言是前端開發(fā)的累贅,是個(gè)雞肋,那個(gè)時(shí)候人們還享受著從一個(gè)a鏈接蹦到另一個(gè)頁(yè)面的web神奇魔術(shù)。后來隨著JavaScript的不斷更新?lián)Q代,他的功能不僅僅是為網(wǎng)頁(yè)添加一點(diǎn)特效了,語(yǔ)言本身的加強(qiáng)以及對(duì)DOM操作能力的提升讓他在前端大放光彩。尤其是ajax的出現(xiàn),讓JavaScript以及整個(gè)web的發(fā)展翻開了嶄新的一頁(yè)。 利用ajax局部刷新頁(yè)面,相信很多人玩得相當(dāng)熟練了。如果整個(gè)頁(yè)面的刷新都是使用ajax,我們可以稱之為一個(gè)webapp,所有的邏輯都是在當(dāng)頁(yè)處理,這種形式的頁(yè)面帶來的體驗(yàn)是十分不錯(cuò)的,減少了那些比較“冗余”的頁(yè)面跳轉(zhuǎn)、新開頁(yè)面等。不過,webapp的代碼是十分不好維護(hù)的,頁(yè)面邏輯太多太深,出點(diǎn)小問題,整個(gè)頁(yè)面就會(huì)癱瘓,而且不方便定位bug,可維護(hù)性很低。 二、PJAX的實(shí)現(xiàn)與應(yīng)用1.場(chǎng)景再現(xiàn)-ajax弊端ajax是一個(gè)非常好玩的小東西,不過用起來也會(huì)存在一些問題。 我們可以利用ajax進(jìn)行無刷新改變文檔內(nèi)容,但是沒辦法去修改URL,有童鞋要問,這里為什么一定要修改URL呢?一個(gè)URL代表一個(gè)特定的網(wǎng)絡(luò)資源,ajax修改了頁(yè)面的內(nèi)容,所以用不同的URL去標(biāo)識(shí)他們,這個(gè)還是挺有必要的。 比如我們?cè)O(shè)計(jì)了一個(gè)單詞查詢的頁(yè)面,比較合理的UR應(yīng)該是http:///word,不同的word對(duì)應(yīng)不同的內(nèi)容,但是如果整個(gè)頁(yè)面都是ajax實(shí)現(xiàn),我們就沒法去修改/word了,當(dāng)然我們可以使用hash如http://#word,但這樣就不能很好的處理瀏覽器的前進(jìn)和后退問題。如:在頁(yè)面中查詢了單詞A的翻譯,接著又查詢了單詞B,這個(gè)時(shí)候?yàn)g覽器的瀏覽歷史會(huì)生成http://#A和http://#B兩個(gè)記錄,可是當(dāng)我們從B轉(zhuǎn)回A的時(shí)候,AJAX的效果還停留在B的狀態(tài)(頁(yè)面顯示的還是單詞B的翻譯)。部分瀏覽器對(duì)此問題引入了onhashchange的接口,只要URL的hash值發(fā)生變化,我們的程序就可以監(jiān)聽并做出相應(yīng)。不過對(duì)于那些木有這個(gè)接口的瀏覽器,就得定時(shí)去判斷hash的變化了。 而這樣的方式對(duì)搜索引擎是十分不友好的,twitter和google約定使用hash bang (#!xxx),也就是hash后面的第一個(gè)字符為感嘆號(hào),這樣的網(wǎng)址他們是會(huì)爬取的,但是其他搜索引擎不支持。PJAX可以在改變頁(yè)面內(nèi)容的同時(shí)也改變他的URL,下面來說說PJAX和他的應(yīng)用。 2.什么是PJAXhistory API中有幾個(gè)新特性,分別是history.pushState和history.replaceState,我們把pushState+AJAX進(jìn)行封裝,合起來簡(jiǎn)單點(diǎn)叫,就是PJAX~ 雖說實(shí)現(xiàn)技術(shù)上沒什么新東西,但是概念上還是有所不同的。 PJAX的基本思路是,用戶點(diǎn)擊一個(gè)鏈接,通過ajax更新頁(yè)面變化的部分,然后使用HTML5的pushState修改瀏覽器的URL地址,這樣有效地避免了整個(gè)頁(yè)面的重新加載。如果瀏覽器不支持history的兩個(gè)新API或者JS被禁用了,那這個(gè)鏈接就只能跳轉(zhuǎn)并重新刷新整個(gè)頁(yè)面了。和傳統(tǒng)的ajax設(shè)計(jì)稍微不同,ajax通常是從后臺(tái)獲取JSON數(shù)據(jù),然后由前端解析渲染,而PJAX請(qǐng)求的是一個(gè)在服務(wù)器上生成好的HTML碎片,如下圖所示:
客戶端向服務(wù)器發(fā)送一個(gè)普通的請(qǐng)求(1),其實(shí)也就是點(diǎn)擊了一個(gè)鏈接,服務(wù)器會(huì)相應(yīng)這個(gè)請(qǐng)求(2),返回一個(gè)html文檔??蛻舳讼蚍?wù)器發(fā)送一個(gè)有PJAX標(biāo)志的請(qǐng)求(3),此時(shí)服務(wù)器只返回一個(gè)html碎片(4)。但是這兩次請(qǐng)求都讓客戶端的URL變化了,希望上面的說明可以讓你明白了PAJX和AJAX的區(qū)別了。 3.PJAX的實(shí)現(xiàn)先看一個(gè)小DEMO吧,這個(gè)DEMO也寫了我半個(gè)多小時(shí),看之前先說明一下,打開你的現(xiàn)代瀏覽器(chrome,F(xiàn)irefox,opera,IE9+等),進(jìn)入gallery頁(yè)面,查看圖片的時(shí)候注意觀察瀏覽器的title和url變化,點(diǎn)擊前進(jìn)后退按鈕也注意查看其變化。我已經(jīng)在瀏覽歷史管理中push了三條歷史記錄。 DEMO地址:http://qianduannotes./demo/PJAX/index.html 如果你還沒有理解上面說的PJAX和AJAX的區(qū)別,看完這個(gè)demo,你應(yīng)該有所領(lǐng)悟吧!在URL變化之后,頁(yè)面并沒有刷新,而是繼續(xù)完成自己的動(dòng)畫(demo中為fadeOut)。 在HTML4,Histroy對(duì)象有下面屬性方法:
在HTML5中,新增了兩個(gè)方法:
當(dāng)點(diǎn)擊“上一張”、“下一張”這兩個(gè)鏈接的時(shí)候,首先通過pushState修改URL以及修改document.title,那這個(gè)時(shí)候你就可以當(dāng)做文檔已經(jīng)進(jìn)入了另外一個(gè)鏈接了,然后該干什么干什么。demo中是讓圖片fadeOut,fadeOut完了之后讓瀏覽器去加載資源,這個(gè)步驟就是正常的AJAX操作啦,沒有什么特殊之處了~ 因?yàn)橹粶?zhǔn)備了三張圖片,所有后臺(tái)寫的也比較簡(jiǎn)單: <?php error_reporting(false); $num = $_GET['num']; if(array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true'){ if($num == 1) { ?> <div class="imgwrap"> <img src="./images/1.jpg" /> </div> <span><a href="num=2" class="next">下一張>></a></span> <?php } else if ($num == 2) { ?> <div class="imgwrap"> <img src="./images/2.jpg" /> </div> <span><a href="num=1" class="previous"><<上一張</a> <a href="num=3" class="next">下一張>></a></span> <?php } else { ?> <div class="imgwrap"> <img src="./images/3.jpg" /> </div> <span><a href="num=2" class="previous"><<上一張</a></span> <?php } } ?> 上面那張圖中,我們看到了,并不是每個(gè)連接都使用PJAX來加載,如果有X_PJAX標(biāo)識(shí),我們才會(huì)添加相應(yīng)的處理。js中稍加注意可以看到: $.ajax({
"url": "./interface.php",
"data": {
"num": num
},
"dataType": "html",
"headers": {
"X_PJAX": true
}
});
請(qǐng)求中: Accept:text/html, */*; q=0.01 Accept-Encoding:gzip,deflate,sdch Connection:keep-alive Host:qianduannotes. User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 X-Requested-With:XMLHttpRequest X_PJAX:true 我在請(qǐng)求的header中加了一個(gè)X_PJAX的頭,而后臺(tái)在處理的時(shí)候也做了判斷: function is_pjax(){ return array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true'; } 并不是一定要求在header頭部中加入X_PJAX的信息,你也可以在url中加入相關(guān)的參數(shù),比如:http://?pjax=1,或者其他方式,只要前后端達(dá)到一個(gè)共識(shí)就行。 三、開源的PJAX庫(kù)已經(jīng)有人對(duì)這個(gè)東西做了封裝,我就不重復(fù)造輪子了。 并不是頁(yè)面中所有的鏈接都需要使用PJAX加載,所有在需要這個(gè)東西的a標(biāo)簽上加一個(gè)屬性,如 四、注意事項(xiàng)
五、參考資料
本文同步自我的github pages
|
|
|