pjax是什么?

pjax 是一个 jQuery 插件,它通过 ajax 和 pushState 技术提供了极速的(无刷新 ajax 加载)浏览体验,并且保持了真实的地址、网页标题,浏览器的后退(前进)按钮也可以正常使用。

pjax 的工作原理是通过 ajax 从服务器端获取 HTML,在页面中用获取到的 HTML 替换指定容器元素中的内容。然后使用 pushState 技术更新浏览器地址栏中的当前地址。

以下两点原因决定了 pjax 会有更快的浏览体验:

  1. 不存在页面资源(JS/CSS)的重复加载和应用;

  2. 如果服务器端配置了 pjax,它可以只渲染页面局部内容,从而避免服务器渲染完整布局的额外开销

项目现状

jQuery-pjax 的维护方向:可能会继续修复重要的 bug,但其功能不会再发生变化,即不会再实现新功能,也不会再扩展现有功能

如何使用pjax?

客户端

客户端设置分两步:

  1. 下载插件,包括 jQuery1.8+,或者 npm 安装,这部分参考文档,不赘述

  2. 初始化 pjax 插件,并有条件的拦截

1
$.fn.pjax

以下代码表示:当 selector 被点击时,执行 ajax 请求,并将返回的 HTML 字符串填充在 container 标记的位置

1
$(document).pjax(selector, [container], options)

参数说明

  • selector:string 类型,用于 click 事件委托 的选择器
  • container:string 类型,用于标识唯一 pjax 容器的选择器
  • options object 类型,包含下列选项

pjax 配置选项

选项 默认值 说明
timeout 650 ajax 超时时间(毫秒),超时后强制刷新整个页面
push true 使用pushState在浏览器中添加历史记录
replace false 替换 URL 地址但不添加浏览器历史记录
maxCacheLength 20 容器元素缓存内容的最大值(次)
version string 或 function,返回当前 pjax 版本
scrollTo 浏览器滚动条的垂直滚动位置。设为 false 时禁止滚动
type “GET” 参考$.ajax
dataType “HTML” 参考$.ajax
container 被替换内容元素的 CSS 选择器
url link.href string 或 function,返回 ajax 请求响应的 URL
target link pjax事件中 relatedTarget 属性的最终值
fragment CSS 选择器,提取 ajax 响应内容中指定的内容片段

可以在全局使用 $.pjax.defaults 对象改变默认配置:

1
$.pjax.defaults.timeout = 1200

服务端

服务端也比较简单,监听 HTTP 的 header 中有 X-pjax 的 ajax 请求,如果有则返回 HTML 片段,而不是整个 HTML

API介绍

$.fn.pjax

最简单常见的 pjax 使用方法如下:

1
$(document).pjax('a', '#pjax-container')

通过这种方式可以让页面中所有的链接都实现 pjax 加载,并指定 #pjax-container 作为容器元素


$.pjax.click

这是一个 $.fn.pjax 内部使用的底层方法,通过此方法可以在 pjax 事件之上做更多的事情。本示例使用当前的 click 上下文来设置一个祖先元素作为容器:

1
2
3
4
5
6
7
if ($.support.pjax) {
$(document).on('click', 'a[data-pjax]',function(event) {
var container = $(this).closest('[data-pjax-container]')
var containerSelector = '#' + container.id
$.pjax.click(event, {container: containerSelector})
})
}

$.pjax.submit

通过 pjax 提交表单

1
2
3
$(document).on('submit', 'form[data-pjax]', function(event) {
$.pjax.submit(event, '#pjax-container')
})

$.pjax.reload

使用 pjax 机制发起一个当前 URL 的请求到服务器,并且通过响应的内容替换容器元素中的内容,同时不添加浏览器历史记录

1
$.pjax.reload('#pjax-container', options)

$.pjax

手动调用 pjax。主要用于非 click 事件发起 pjax 请求的情况

1
2
3
4
function applyFilters() {
var url = urlForFilters()
$.pjax({url: url, container: '#pjax-container'})
}

事件

除了 pjax:click 和 pjax:clicked,其他所有 pjax 事件都是在 pjax 容器元素上触发的。

事件 取消 参数 说明
pjax 链接事件的生命周期
pjax:click ✔︎ options 链接被激活的时候触发;取消的时候阻止 pjax
pjax:beforeSend ✔︎ xhr, options 可以设置 XHR 头
pjax:start xhr, options
pjax:send xhr, options
pjax:clicked options pjax 通过链接点击已经开始之后触发
pjax:beforeReplace contents, options 从服务器端加载的 HTML 内容完成之后,替换当前内容之前
pjax:success data, status, xhr, options 从服务器端加载的 HTML 内容替换当前内容之后
pjax:timeout ✔︎ xhr, options 在 options.timeout 之后触发;除非被取消,否则会强制刷新页面
pjax:error ✔︎ xhr, textStatus, error, options ajax 请求出错;除非被取消,否则会强制刷新页面
pjax:complete xhr, options
浏览器前进后退事件的生命周期
pjax:popstate direction事件的属性: “back”/“forward”
pjax:start null, options 内容替换之前
pjax:beforeReplace contents, options 在用缓存中的内容替换 HTML 之前
pjax:end null, options 替换内容之后
pjax:callback null, options 页面脚本加载完成后(Admui 项目)

如果您使用了加载指示(如 loading 图标或 “加载中” 的文字),pjax:send 和 pjax:complete 这两个事件会比较有用。它们只有在 XHR 请求(而不是从缓存中加载内容)时才会被触发:

1
2
3
4
5
6
$(document).on('pjax:send', function() {
$('#loading').show()
})
$(document).on('pjax:complete', function() {
$('#loading').hide()
})

以下是禁用 pjax:timeout 事件的示例:

1
2
3
4
$(document).on('pjax:timeout', function(event) {
// Prevent default timeout redirection behavior
event.preventDefault()
})