PJAX

分类专栏:
前端相关

文章标签:
Java自学
前端
原创

PJAX

PJAX项目地址

PJAX是什么

pjax是一个jQuery插件,它使用ajax和pushState通过真正的永久链接,页面标题和后退按钮提供快速浏览体验

PJAX好处

用户体验提升,不做页面跳转,只是在站内页面刷新,大部分请求(css/js)都不会重新获取,极大的减少带宽消耗和服务器消耗

PJAX的工作原理

pjax的工作方式是通过ajax从服务器获取HTML,然后用加载的HTML替换页面上容器元素的内容

然后使用pushState技术更新浏览器中的当前URL

由于以下两个原因,这使得页面导航更快:

1)没有页面资源(JS,CSS)被重新执行或重新应用

2)如果服务器配置为使用pjax,则它只能渲染部分页面内容,从而避免了可能昂贵的完整布局渲染

PJAX用法

中文文档

$.fn.pjax

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

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

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

如果正在迁移已有网站,可能不希望在每个地方都使用pjax

那么可以用data-pjax来注明这是一个pjax链接,然后使用a[data-pjax]来代替全局选择器a

或者,也可以使用在<div data-pjax>容器中的<a data-pjax href="...">链接作为选择器

$(document).pjax('[data-pjax] a, a[data-pjax]', '#pjax-container')

服务器端配置

在服务器端可通过检查指定的X-PJAXHTTP头来识别pjax请求,并且只渲染指定的HTML内容,这也就意味着在浏览器端我们不用重新渲染整个页面,只替换指定容器元素(在我们的示例中是 #pjax-container)中的内容即可

下面的示例是在Ruby on Rails中的实现方法:

def index
  if request.headers['X-PJAX']
    render :layout => false
  end
end

如果想了解比上述方案更为自动化的方案,请查看 Turbolinks

参数

$.fn.pjax 方法概述:

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

1)selector:string类型,用于click 事件委托 的选择器

2)container:string类型,用于标识唯一pjax容器的选择器

3)options object类型,包含下列选项

pjax配置选项
选项 默认值 说明
timeout 650 ajax超时时间(毫秒),超时后强制刷新整个页面
push true 使用 pushState 在浏览器中添加历史记录
replace false 替换URL地址但不添加浏览器历史记录
maxCacheLength 20 容器元素缓存内容的最大值(次)
version string或function,返回当前pjax版本
scrollTo 0 浏览器滚动条的垂直滚动位置。设为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对象改变默认配置:

$.pjax.defaults.timeout = 1200

$.pjax.click

这是一个$.fn.pjax内部使用的底层方法,通过此方法可以在pjax事件之上做更多的事情

使用当前的click上下文来设置一个祖先元素作为容器:

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})
  })
}

注意 通过$.support.pjax我们明确浏览器是支持pjax的

但我们没有使用$.fn.pjax,所以我们应该忽略绑定此事件的处理,除非浏览器实际上要使用pjax

$.pjax.submit

通过pjax提交表单

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

$.pjax.reload

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

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

$.pjax

手动调用pjax

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

如果可以获得click事件,请使用$.pjax.click(event)来代替

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

事件

除了pjax:clickpjax: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, textStatus, options 无论结果如何,都在ajax响应完成后触发
pjax:end 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项目)

注意 由于Admui项目对本插件做了一些修改,建议不要使用官方原版插件替换

如果使用了加载指示(如loading图标或“加载中”的文字),pjax:sendpjax:complete这两个事件会比较有用

它们只有在XHR请求(而不是从缓存中加载内容)时才会被触发:

$(document).on('pjax:send', function() {
  $('#loading').show()
})
$(document).on('pjax:complete', function() {
  $('#loading').hide()
})

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

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

高级配置

在新页面中重新初始化插件/工具

pjax的特点是它不会刷新页面即可获取并插入新内容

但是,如果其他jQuery插件(或库)为页面内容绑定了加载事件(如DOMContentLoaded),那么这些事件是无效的

比较常用的一种做法是,在更新的页面内容范围内,重新初始化插件

$(document).on('ready pjax:end', function(event) {
  $(event.target).initializeMyPlugin()
})

该方法可以让$.fn.initializeMyPlugin()在页面普通加载和pjax加载时(点击链接或浏览器前进后退按钮之后)都能被调用

强制重载的响应类型

默认情况下,如果pjax从服务器收到以下响应之一,则会强制重载页面:

  • 页面包含<html>标签,没有明确指定fragment选择器时。 pjax就会认为服务器端没有正确配置pjax响应
  • 如果配置了fragment选项,pjax将根据该选择器提取页面内容
  • 空白页面。pjax就会认为服务器端无法提供正确的pjax内容
  • HTTP状态码为4xx或5xx,表示某些服务器错误

改变浏览器URL

如果服务器端需要改变浏览器地址栏中URL(如HTTP重定向),可以通过设置X-PJAX-URL头来实现:

def index
  request.headers['X-PJAX-URL'] = "http://example.com/hello"
end

重载布局

静态资源或页面发生变化时,布局可被强制进行重载

首先,用一个自定义的meta标签在页面head中初始化layout版本

<meta http-equiv="x-pjax-version" content="v123">

然后,在服务器端设置相同的X-PJAX-Version

if request.headers['X-PJAX']
  response.headers['X-PJAX-Version'] = "v123"
end

部署后,版本不同时整个页面会强制重载,会重新发起请求来获取新的布局和相关资源

  • 作者:潘震
  • 评论

    留言