摘要:是一款可愛的小插件,將和瀏覽器的封裝到一起,解決了單純使用進行無刷新加載時對搜索引擎的不友好,并且節省了開支提高了瀏覽速度,明顯地優化了用戶體驗。是提供的,是對瀏覽器歷史對象的增強。
知識要點pjax 是一款可愛的 jQuery 小插件,將 ajax 和瀏覽器的 pushState API 封裝到一起,解決了單純使用 ajax 進行無刷新加載時對搜索引擎的不友好,并且節省了 HTTP 開支、提高了瀏覽速度,明顯地優化了用戶體驗。
ajax 自不多說,在這里負責攜帶 pjax 標識請求后端,將生成好的 html 碎片(注意不是前端取回JSON來進行渲染)取回,然后 jQuery 將它替換到 DOM 當中。
pushState 是 html5 提供的API,是對瀏覽器歷史對象 history 的增強。了解 Javascript 的都知道 BOM (瀏覽器對象模型),而 window 則是 BOM 的具體實現,history 則是window 的子對象,這個 pushState 就屬于 window.history 的一個方法。簡單明了。
接下來,我們進一步了解一下 pushState 。
先看下面的一段代碼:
var stateObj = { foo: "bar" } history.pushState(stateObj, "title", "bar.html")
首先聲明一個狀態對象,能夠儲存任何可序列化數據,比如將 html 碎片存儲于此,但大小有限制(640k),可以使用 localStorage 等機制。當然也可以不使用,它的取舍我們后面具體實施時會提到。
pushState 方法往瀏覽器歷史棧里插入一條歷史項,執行完成之后,瀏覽器會立即將歷史項中的 url(bar.html) 顯示在地址欄中,(url 接受的是相對地址,會自動補上域名),但不會將其加載。而 "title" 在這里暫時沒有用處,瀏覽器不會用它來修改頁面標題,可以填 null。
那什么時機調用此方法?監聽你需要 pjax 效果的超鏈接的 click 事件,禁用默認的跳轉,然后 do that。但講到這里你可能會想到,如果用戶進行瀏覽器的前進和后退操作,還是會執行跳轉加載,那該如何處理呢?
這就要用到 pjax 不可忽視的關鍵角色 -- popstate 事件。這個事件只在瀏覽器的前進和后退操作時觸發,所以通過監聽它,如法炮制上述操作即可 。至此,我們每一次的瀏覽訪問都向搜索引擎伸出了友好的橄欖枝。
講到這里,我們大體了解了 pjax 的流程,就是監聽所有需要 pjax 效果的超鏈接,使用 ajax 和后端達成協議取回 html 碎片并填充到 DOM 當中,pushState 負責將瀏覽器地址欄修改成我們想要的 URL,并且往歷史棧中增加一個歷史項,通過監聽 popstate,讓瀏覽器的前進和后退也 pjax 化。
最后,replaceState 這個 history API 也有必要介紹一下。當你需要將當前激活的歷史項從歷史棧中徹底抹去并替換成另一個,那用它就對了,使用方法和 pushState 完全一樣,最常見的使用場景是使用 pjax 刷新頁面。
具體實施pjax 的安裝配置需要前后端配合進行。前后端的輪子都有不少現成的,但前端的輪子做不到開箱即用,這是因為 pjax 的實現需要結合項目的具體代碼進行實施,下面我會分別講解。
前端采用最流行的 defunkt/jquery-pjax。話不多說,文檔寫的都很詳細。這里主要根據源碼提幾點需要注意的地方:
綁定選擇器時,推薦使用 data-pjax 屬性,這個屬性會自動尋找標簽及其子標簽中的超鏈接,綁定 click.pjax (順便注意這里的事件命名空間,目的是為了主動 trigger 時能區別對待 click) 事件。
$(document).pjax("[data-pjax] a, a[data-pjax]", "#pjax-container")
jquery-pjax 做到了自動向后兼容,不需要多帶帶做兼容性判斷,放心調用 pjax 方法即可。
如果你的后端程序響應慢,pjax 會不耐煩的直接跳轉,要么將后端程序或者網絡環境優化,要么讓 pjax 稍微耐心一點:
$.pjax.defaults.timeout = 1600 /*默認 650 毫秒*/
之所以說 pjax 不是開箱即用,主要是因為所有 js 腳本的調用會在第二次執行 pjax 方法時失效。我剛開始遇到這個問題時,一頭霧水,折騰了許久而不得解,然后在 laravel china 發帖求助,很快站長龍哥就站出來,耐心細致的解答了我的疑惑。仔細研究了源碼,我發現了其中兩個有趣的函數:
var container = extractContainer("", xhr, options) executeScriptTags(container.scripts)
字面意思是將取回的 html 碎片 進行加工處理成一個容器對象,并處理其中的腳本標簽,那為什么第一次之后的 pjax 就沒執行我的腳本呢?我們繼續閱讀兩個函數體內的關鍵代碼:
extractContainer :
// Gather all script[src] elements obj.scripts = findAll(obj.contents, "script[src]").remove() obj.contents = obj.contents.not(obj.scripts)
將 html 碎片中的所有帶 src 的腳本刪除并儲存在容器對象的 scripts 屬性中,將去除了 scripts 的 html 碎片內容賦給 contents 屬性。看到這里,你可能會大概明白了 pjax 的用意。繼續看另一個函數體的內容:
executeScriptTags :
if (!scripts) return var existingScripts = $("script[src]") scripts.each(function() { var src = this.src var matchedScripts = existingScripts.filter(function() { return this.src === src }) if (matchedScripts.length) return var script = document.createElement("script") var type = $(this).attr("type") if (type) script.type = type script.src = $(this).attr("src") document.head.appendChild(script) })
獲取目前 DOM 中的所有帶 src 的腳本,然后和 html 碎片中的腳本逐個做比對,如果碎片中有新的腳本就將其插入到 head 標簽的最后。啊哈~ pjax 這么做是確保不會重復請求任何已經下載過的腳本文件,節省 HTTP 開支。但這么做的弊端就是本段開頭說的那個問題,那如何解決呢?
靈活運用 pjax 提供的事件。 要解決上述問題,我們可以監聽 pjax:end 事件,當然 pjax:success 和 pjax:complete 也行,區別不大 :
$(document).on("pjax:end", function() { self.blogBootUp() })
當 pjax 生命周期結束,主動調用一下腳本啟動程序即可。這里,我將我所有的腳本啟動程序都封裝到 blogBootUp 中了,具體的代碼請移步我的 Blog 項目。
使用了 pjax ,就相當于我們阻斷了瀏覽器的常規瀏覽機制,使用相關接口去重寫瀏覽邏輯。對于瀏覽器的前進和后退功能,我們監聽了 popstate 事件去使用 pjax,但在常規的情況下,瀏覽器是有緩存的,所以我們能秒進或秒退,但如果 pjax 不優化這一塊,那前進和后退也要去請求服務器的話會付出不少的代價。查看 pjax 源碼發現,作者是做了緩存處理的,通過兩個關鍵函數 cachePush 和 cachePop 來模擬瀏覽器緩存,只不過是存在數組中(也就是內存中),如果你想達到 真正的 webApp 的水準,我覺得還需要配合 localStorage 和 WebSocket 等類似的機制來穩健的存儲數據和靈活的控制頁面的緩存時間,當然這就比較復雜了,待以后再去實踐好了。
后端我選用了 JacobBennett/pjax。兼容 laravel 5.* ,采用了中間件的形式,所以使用起來很簡單,直接將中間件引入到 app/Http/Kernel.php 中即可。讀了下源碼,發現無非是使用了一個 DOM 爬蟲根據客戶端 header 傳遞的 pjax 標識和 pjax 容器標識 (就是 selector),抓取 laravel 響應對象內容中的 title 和 容器內容,然后連綴在一起復寫回去,返回給客戶端。
最后,再推薦使用一個加載效果動畫的 javascript 插件,配合 pjax 使用毫無違和感。rstacruz/nprogress,文檔寫的很簡潔明了,有專門針對 pjax 的使用說明,用上之后,還是相當酷炫的。
參考資料在 Laravel 應用中使用 pjax 進行頁面加速
PJAX的實現與應用
HTML5 Page Cache with pjax + Web Storage + Firebase
defunkt/jquery-pjax
JacobBennett/pjax
原文鏈接:https://macken.me/article/speed-up-your-website-with-pjax
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/22097.html
摘要:是一款可愛的小插件,將和瀏覽器的封裝到一起,解決了單純使用進行無刷新加載時對搜索引擎的不友好,并且節省了開支提高了瀏覽速度,明顯地優化了用戶體驗。是提供的,是對瀏覽器歷史對象的增強。 showImg(https://segmentfault.com/img/remote/1460000007640529?w=1008&h=569); pjax 是一款可愛的 jQuery 小插件,將 a...
摘要:最重要的就是找一個適合自己的主題了。事實上,免費主題也非常多,而且很多的免費主題在功能上和界面美觀上已經大大超過了付費的主題。加上這些主題都是開源的,基本上可以在上找得到源碼,安全性是沒有問題,主題的作者也在不斷更新當中。WordPress最重要的就是找一個適合自己的主題了。好一點的WordPress主題基本上都是要收費的,而且價格還不便宜,這導致了不少的新手朋友們很為難。而有時我們僅僅根據...
摘要:初步理解如果最近打電話給武漢的小伙伴,他說信號不好,那么相信我,他肯定不是真的信號不好,也不是不想和你說話,而是他可能在冰箱里。。。 初步理解 如果最近打電話給武漢的小伙伴,他說信號不好,那么相信我,他肯定不是真的信號不好,也不是不想和你說話,而是他可能在冰箱里。。。武漢的天氣從來都是喜怒無常的,是吧,屌絲氣十足,今年也是絲毫看不出有任何逆襲的跡象和可能性,當然咱也沒必要去操那個心;好...
摘要:項目概述糖果盒子是采用開發的站點導航應用,專注分享優質開發資源站點,希望成為開發人員最喜愛的的書簽導航。線上地址糖果盒子開發者的書簽導航地址求環境要求部署安裝本項目代碼使用框架開發,本地開發環境使用。 showImg(https://segmentfault.com/img/remote/1460000012018405?w=3346&h=1950);showImg(https://s...
摘要:項目概述糖果盒子是采用開發的站點導航應用,專注分享優質開發資源站點,希望成為開發人員最喜愛的的書簽導航。線上地址糖果盒子開發者的書簽導航地址求環境要求部署安裝本項目代碼使用框架開發,本地開發環境使用。 showImg(https://segmentfault.com/img/remote/1460000012018405?w=3346&h=1950);showImg(https://s...
閱讀 3041·2021-09-22 14:59
閱讀 1874·2021-09-22 10:02
閱讀 2114·2021-09-04 16:48
閱讀 2264·2019-08-30 15:53
閱讀 2969·2019-08-30 11:27
閱讀 3406·2019-08-29 18:35
閱讀 965·2019-08-29 17:07
閱讀 2674·2019-08-29 13:27