pjax 即 pushState ajax,它被封裝變成了一個 jQuery 擴充功能以方便使用。 pjax 主要用來解決 HTML 頁面局部刷新 url 不更新和不支援後退和前進的問題,提升使用者體驗。
pjax原理
pjax 的實作是利用 HTML5 的 pushState() 和 replaceState() 新特性和 ajax 結合實作。 pushState() 和 replaceState() 用來操作 State(狀態)對象,即可新增和修改歷史記錄,進而更新 url 和提供前進、後退操作 ajax 實作資料的非同步載入進而局部刷新。
工作流程圖
#原始碼分析
- #pjax支援判斷
(function($){ $.support.pjax = window.history && window.history.pushState && window.history.replaceState && // pushState isn't reliable on iOS until 5. !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/) if ($.support.pjax){ enable() //启用 } else { disable() //禁用 } })(jQuery)
- enable()
function enable() { $.fn.pjax = fnPjax //注册jQuery的pjax方法 $.pjax = pjax //注册pjax对象 $.pjax.enable = $.noop $.pjax.disable = disable $.pjax.click = handleClick //注册click回调 $.pjax.submit = handleSubmit //注册submit回调 $.pjax.reload = pjaxReload //注册reload回调 $.pjax.defaults = {} //设置默认值 $(window).on('popstate.pjax', onPjaxPopstate) //绑定popstate事件回调 }
$.noop
是一個空方法,不做任何事,即function(){}
。 popstate.pjax
是JS 事件的命名空間寫入法,popstate
是事件類型,每當啟動的歷史記錄發生變化時(瀏覽器操作前進、後退按鈕、呼叫back()或go() 方法),都會觸發popstate 事件,但呼叫pushState()、replaceState() 不會觸發popstate 事件。 .pjax
是該事件的命名空間,這樣方便解綁定指定命名空間的事件回應,在綁定匿名函數時常使用,例如:this.on('click.pjax', selector , function(event){})
。
- fnPjax()
此方法傳回一個 jQuery 對象,等同於 $.fn.pjax。
return this.on('click.pjax', selector, function(event) { //获取pjax配置信息 options = optionsFor(container, options) //自动绑定click事件响应 return this.on('click.pjax', selector, function(event) { var opts = options if (!opts.container) { opts = $.extend({}, options) //如果不配置container,则默认获取data-pjax属性值对应的 opts.container = $(this).attr('data-pjax') } handleClick(event, opts) //调用click回调 }) }
- pjax()
// Use it just like $.ajax: // // var xhr = $.pjax({ url: this.href, container: '#main' }) // console.log( xhr.readyState ) // // Returns whatever $.ajax returns. function pjax(options) { //获取设置 options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options) //判断检测 if (containerType !== 'string') /** * ajax响应回调注册 */ //beforeSend options.beforeSend = function(xhr, settings) { //设置pjax头信息,供后端做兼容处理 xhr.setRequestHeader('X-PJAX', 'true') xhr.setRequestHeader('X-PJAX-Container', options.container) //设置超时 } //complete options.complete = function(xhr, textStatus) { //绑定pjax:complete事件 fire('pjax:complete', [xhr, textStatus, options]) //绑定pjax:end事件 fire('pjax:end', [xhr, options]) } //error options.error = function(xhr, textStatus, errorThrown) { //绑定pjax:error事件 fire('pjax:error', [xhr, textStatus, errorThrown, options]) } //success,重点 options.success = function(data, status, xhr) { //判断检测 if (currentVersion && latestVersion && currentVersion !== latestVersion) ... ... window.history.replaceState(pjax.state, container.title, container.url) //绑定pjax:beforeReplace事件 fire('pjax:beforeReplace', [container.contents, options], { state: pjax.state, previousState: previousState }) //渲染页面 context.html(container.contents) //绑定pjax:success事件 fire('pjax:success', [data, status, xhr, options]) } //初始化ajax var xhr = pjax.xhr = $.ajax(options) if (xhr.readyState > 0) { //缓存页面cache cachePush(pjax.state.id, [options.container, cloneContents(context)]) //pushState window.history.pushState(null, "", options.requestUrl) //绑定pjax:start事件 fire('pjax:start', [xhr, options]) //绑定pjax:send事件 fire('pjax:send', [xhr, options]) } //返回jQuery对象 return pjax.xhr }
##1) handleClick()
// Examples // // $(document).on('click', 'a', $.pjax.click) // // is the same as // $(document).pjax('a') // // Returns nothing. function handleClick(event, container, options) { options = optionsFor(container, options) //环境检测 if (link.tagName.toUpperCase() !== 'A') ... ... //绑定pjax:click事件 var clickEvent = $.Event('pjax:click') $link.trigger(clickEvent, [opts]) //执行pjax pjax(opts) //成功则阻止默认行为 event.preventDefault() //绑定pjax:clicked事件 $link.trigger('pjax:clicked', [opts]) }
2 )handleSubmit()
// Examples // // $(document).on('submit', 'form', function(event) { // $.pjax.submit(event, '[data-pjax-container]') // }) // // Returns nothing. function handleSubmit(event, container, options) { options = optionsFor(container, options) //环境检测 if (form.tagName.toUpperCase() !== 'FORM') ... ... //默认配置 var defaults = { type: ($form.attr('method') || 'GET').toUpperCase(), url: $form.attr('action'), container: $form.attr('data-pjax'), target: form } if (defaults.type !== 'GET' && window.FormData !== undefined) { //POST时data域 defaults.data = new FormData(form) } //执行pjax pjax($.extend({}, defaults, options)) //成功则阻止默认行为 event.preventDefault() }
3)pjaxReload()
// Reload current page with pjax. function pjaxReload(container, options) { var defaults = { //当前url url: window.location.href, push: false, replace: true, scrollTo: false } //执行pjax return pjax($.extend(defaults, optionsFor(container, options))) }
4)onPjaxPopstate()
// popstate handler takes care of the back and forward buttons function onPjaxPopstate(event) { //环境监测 if (state && state.container) ... ... //获取页面cache var cache = cacheMapping[state.id] || [] //绑定pjax:popstate事件 var popstateEvent = $.Event('pjax:popstate', { state: state, direction: direction }) container.trigger(popstateEvent) if (contents) { //有页面cache,直接渲染页面 //绑定pjax:start事件 container.trigger('pjax:start', [null, options]) //绑定pjax:beforeReplace事件 var beforeReplaceEvent = $.Event('pjax:beforeReplace', { state: state, previousState: previousState }) container.trigger(beforeReplaceEvent, [contents, options]) //渲染页面 container.html(contents) //绑定pjax:end事件 container.trigger('pjax:end', [null, options]) } else { //无页面cache,执行pjax pjax(options) } }
pjax使用
容易使用pjax 了。
客戶端
pjax 支援 options 設定和事件機制。
- options配置
#參數名稱 | 預設值 | ##說明|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
650 | ajax 逾時時間(單位ms),逾時後會執行預設的頁面跳轉,所以逾時時間不應過短,不過一般不需要設定 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
true | #使用window.history.pushState 改變地址列url(會新增新的歷史記錄) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
false | #使用window.history.replaceState 改變地址列url(不會新增歷史記錄) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
20 | 快取的歷史頁面數量(pjax 載入新頁面前會把原頁面的內容快取起來,快取載入後其中的腳本會再執行) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
0 | 頁面載入後垂直捲動距離(與原始頁面保持一致可使過度效果更平滑) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#「GET」 | ajax 的參數,http 請求方式 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
「html」 | ##ajax 的參數,回應內容的Content-Type||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
用於尋找容器的CSS 選擇器,[container] 參數沒有指定時使用 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#link.href##要跳轉的連接,預設a 標籤的href 屬性 | fragment | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#使用回應內容的指定部分(css 選擇器)填入頁面,服務端不進行處理導致全頁面請求的時候需要使用該參數,簡單的說就是對請求到的頁面做截取 |
为了方便扩展,pjax 支持一些预定义的事件。
客户端通过以下 2 个步骤就可以使用 pjax :
JS<script></script> /** * 方式1 监听按钮父节点事件 */ $(document).pjax(selector, [container], options); /** * 方式2 直接监听按钮,可以不用指定容器,默认使用按钮的data-pjax属性值查找容器 */ $("a[data-pjax]").pjax(); /** * 方式3 主动绑定点击事件监听 */ $(document).on('click', 'a', $.pjax.click); $(document).on('click', 'a', function(event) { //获取container var container = $(this).closest('[data-pjax-container]'); //click回调 $.pjax.click(event, container); }); /** * 方式4 主动绑定表单提交事件监听 */ $(document).on('submit', 'form', function(event) { //获取container var container = $(this).closest('[data-pjax-container]'); //submit回调 $.pjax.submit(event, container); }); /** * 方式5 加载内容到指定容器 */ $.pjax({url: this.href, container: '#main'}); /** * 方式6 重新加载当前页面容器的内容 */ $.pjax.reload('#container'); YII在 Yii 中,已经将 pjax 封装成了 widgets,故在渲染时如下使用即可: //view <?php Pjax::begin(); ?> ... ... <?php Pjax::end(); ?> pjax 封装成的 widgets 源码文件 public function registerClientScript() { //a标签的click if ($this->linkSelector !== false) { $linkSelector = Json::htmlEncode($this->linkSelector !== null ? $this->linkSelector : '#' . $id . ' a'); $js .= "jQuery(document).pjax($linkSelector, \"#$id\", $options);"; } //form表单的submit if ($this->formSelector !== false) { $formSelector = Json::htmlEncode($this->formSelector !== null ? $this->formSelector : '#' . $id . ' form[data-pjax]'); $submitEvent = Json::htmlEncode($this->submitEvent); $js .= "\njQuery(document).on($submitEvent, $formSelector, function (event) {jQuery.pjax.submit(event, '#$id', $options);});"; } $view->registerJs($js); } 服务端由于只是 HTML5 支持 pjax,所以后端需要做兼容处理。通过 /** * IndexController示例 */ public function actionIndex() { $dataProvider = new CActiveDataProvider('Article', array( 'criteria' => array('order' => 'create_time DESC') )); //存在X-Pjax头,支持pjax if (Yii::$app->getRequest()->getHeaders()->get('X-Pjax')) { //返回局部页面 $this->renderPartial('index', array( 'dataProvider' => $dataProvider, )); } else { //返回整个页面 $this->render('index', array( 'dataProvider' => $dataProvider, )); } } pjax失效情况在以下 9 种情况时候 pjax 会失效,源码部分如下: //click回调 function handleClick(event, container, options) { ... // 1. 点击的事件源不是a标签。a标签可以对旧版本浏览器的兼容,因此不建议使用其他标签注册事件 if (link.tagName.toUpperCase() !== 'A') throw "$.fn.pjax or $.pjax.click requires an anchor element" // 2. 使用鼠标滚轮点击、点击超链接的同时按下Shift、Ctrl、Alt和Meta if (event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return // 3. 跨域 if (location.protocol !== link.protocol || location.hostname !== link.hostname) return // 4. 当前页面的锚点定位 if (link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location)) return // 5. 已经阻止元素发生默认的行为 if (event.isDefaultPrevented()) return ... var clickEvent = $.Event('pjax:click') $(link).trigger(clickEvent, [opts]) // 6. pjax:click事件回调中已经阻止元素发生默认的行为 if (!clickEvent.isDefaultPrevented()) { pjax(opts) } } //pjax function pjax(options) { options.beforeSend = function(xhr, settings) { //7. ajx超时 timeoutTimer = setTimeout(function() { if (fire('pjax:timeout', [xhr, options])) xhr.abort('timeout') }, settings.timeout) } options.success = function(data, status, xhr) { //8. 当前页面和请求的新页面版本不一致 if (currentVersion && latestVersion && currentVersion !== latestVersion) { return } //9. ajax失败 context.html(container.contents) } 其他方案除了使用 pjax 解决局部刷新并支持前进和后退问题外,也可以使用 browserstate/history.js + ajax 方案来实现 |
以上是Javascript PJAX 原理與使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器