07月01, 2017

Pjax参考文档

pjax = pushState + ajax

pjax是一个jQuery插件,它通过ajaxpushState状态推送来提供极速浏览体验,支持真实固定链接,页面标题以及可进退的功能。

pjax的运作原理是通过ajax方式从服务器获取目标内容,并再指定页面元素中进行替换。然后会通过pushState在地址栏更新链接地址。之所以这种操作方式会代理极速的浏览体验,主要是有以下两方面原因:

  • 不会有静态资源(JS、CSS)内容的在此执行或者再次请求
  • 如果服务端已经针对pjax做过特殊配置,就可以实现只渲染指定部分的内容,来避免潜在的耗时耗资源的整页重载

当前项目状态

jquery-pjax当前并没有在维护。或许会有持续的bug修复,但是主要特性是不会再更新啦。也就是说不会再有新特性的加入或者现有功能的增强。

安装

pjax依赖jQuery 1.8 或者更高版本

npm

$ npm install jquery-pjax

单独引入

下载jquery.pjax.js并在目标页面引入:

curl -LO https://raw.github.com/defunkt/jquery-pjax/master/jquery.pjax.js

使用

$.fn.pjax

最常见的使用方式:

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

上面的代码会监听所有a标签,并且指定内容目标容器到#pjax-container中。 如果你在改造一个已经存在的页面,那么针对所有a标签都开启pjax并不合适。应该在目标a标签上加上data-pjax属性,然后使用'a[data-pjax]'来指定这部分a标签来开启pjax功能。或者使用此选择器去选择<div data-pjax>容器中的<a data-pjax href=标签:

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

服务端配置

比较理想的实现方法是,服务端去检测每个请求中的X-PJAXheader属性,如果有这个属性,那么只会将目标HTML内容替换到#pjax-container容器中,而忽略页面上的其他布局部分代码。下面是在Ruby on Rail中的实践实例:

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

查看是否已经有你喜欢的框架搭配的pjax插件。

参数

$.fn.pjax方法概述:

$(document).pjax(selector, [container], options)
  • selector:表示要绑定pjax特性的代理选择器event delegation.
  • container:表示要发生pjax替换的容器选择器
  • options:表示pjax的配置属性,具体如下表

pjax配置属性

key默认值描述
timeout650ajax超时时间设置,毫秒为单位,pjax请求超时之后,将会强制发起整页刷新
pushtrue使用pushState在浏览器导航中加入一条历史浏览器记录
replacefalse修改地址栏,并且不会影响浏览器历史浏览记录
maxCacheLength20pjax对于上次请求内容的缓存最大长度
version字符串或者方法来定义当前pjax版本
scrollTo0pjax请求内容之后是否出发页面滚动,如果不需要滚动,设置为false
typeGET参考 [$.ajax]
dataTypehtml参考 [$.ajax]
containerhtmlpjax请求的目标替换容器选择器
urllink.href设置当前pjax请求的目标url,可以是字符串或者返回字符串url的方法
targetlink设置pjax eventsrelatedTarget属性值
fragment 需要从ajax返回的内容中筛选出的目标选择器fragment指向的内容

可以通过$.pjax.defaults来修改全局配置属性:

$.pjax.defaults.timeout = 1200

$.pjax.click

这是一个pjax底层使用的方法。如果需要对pjax event有自定义的操作,可以使用这个方法。

这个例子会将当前点击的上下文中的第一个父级元素设置为pjax目标容器:

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插件,防止页面未加载pjax插件的情况下执行pjax事件的绑定

$.pjax.submit

pjax方式提交表单

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

$.pjax.reload

使用pjax初始化一个当前链接的请求,并使用pjax机制来请求目标内容替换到#pjax-container容器中,同时不会增加浏览器历史浏览记录。

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

$.pjax

手动pjax调用方式。当你想用非点击的方式触发一个pjax请求,就可以使用它。如果能够访问到点击事件click event,可以用$.pjax.click(event)来代替它。

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

Events 事件

pjax:clickpjax:clicked之外,其他所有的pjax events都出发自pjax绑定的目标容器。

事件名称 能否取消 参数 特别提示
pjax链接的事件生命周期
pjax:click ✔︎ event, pjax 由链接出发的pjax事件,可以cancel来取消pjax
pjax:beforeSend ✔︎ xhr, options 可以设置XHR headers
pjax:start event, xhr, pjax
pjax:send event, xhr, pjax
pjax:clicked options pjax绑定的链接被点击之后触发
pjax:beforeReplace event, contents, pjax pjax完成服务器请求之后,替换目标内容之前
pjax:success event, data, status, xhr, pjax 替换目标容器内容之后
pjax:timeout ✔︎ xhr, options 超过 options.timeout设置的超时事件未相应;会发起整页刷新,除非发起取消事件
pjax:error ✔︎ xhr, textStatus, error, options ajax error事件;会发起整页刷新,除非发起取消事件
pjax:complete event, xhr, textStatus, pjax ajax请求完成之后总会执行,不管返回什么结果
pjax:end event, xhr, pjax
浏览器前进/后退事件生命周期
pjax:popstate 浏览器前进后退事件方向: "back"/"forward"
pjax:start null, options pjax目标内容替换之前
pjax:beforeReplace contents, options 马上替换目标内容之前,内容来自缓存
pjax:end null, options 目标内容替换之后

如果你想实现自己的加载中提示效果,那pjax:send & pjax:complete这对事件是你最好的选择。这两个事件会在XHR request生成之后触发,但是从缓存价值内容并不会触发这两个事件:

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

用取消请求来处理超时事件,可以避免加载中提示错误的显示在页面上:

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

高级配置

在新页面上重新初始化插件/部件

pjax的关键点就是从服务器获取内容,并替换到指定容器,并不会刷新整个页面。然而,其他的jQuery插件或者库如果在页面上设置了加载即执行的事件,并不会在pjax执行完成之后在此执行(比如DOMContentLoaded)。因此在被更新的目标容器中进行这些插件的重新初始化是必须的。可以这样做:

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

这种操作,可以保证$.fn.initializeMyPlugin()在正常的页面刷新后被执行,也可以在pjax方式进行前进后退也可以正常执行(不管是点击链接还是点击浏览器的前进后退按钮)。

会导致整页刷新的响应类型

默认情况下,当pjax接受到以下几种情况就会强制发起整页刷新:

  • 当返回的页面内容包含<html>标签,并且未显示配置fragmenr参数。Pjax就会认为服务端未对pjax做相应配置。如果fragment参数设置过,那么pjax会根据fragment选择器从返回的页面内容中选择指定内容进行渲染。
  • 空白页面内容。Pjax会认为服务端无法响应正确的内容。
  • HTTP响应代码是4XX或者500,以及其他服务端错误。

对浏览器地址栏的影响

如果服务端需要在pjax请求完成之后指定浏览器地址(比如重定向),可以通过设置头属性X-PJAX-URL

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

布局重新加载

布局内容可以在页面资源或者html内容发生变化的情况下发起强制整页刷新 首先在初始布局头部分设置自定义meta tag.

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

然后在服务端,设置为与页面一样的X-PJAX-Version属性。

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

部署一次网页,并设置新的版本变量,来达到下次请求时强制整页刷新的目的,这样就加载啦心的布局以及资源。

Github主页

本文链接:https://strongme.cn/post/pjax-doc-cn.html

-- EOF --

Comments