What is pjax?
Now many websites( facebook, twitter ) All support such a way of browsing, when you click on a link in a site, it is not a page jump, but just a site page refresh. This user experience, compared to the whole page flashing, It's much better. Among them, there is an important part. These websites'ajax refresh supports the browser history. While refreshing the page, the address above the browser address field will be changed, and the browser's fallback function can also be used to return to the previous page. So if we want to achieve such a function, how do we do it? I found that pjax provides a script to support such a function. The pjax project address is https://github.com/defunkt/jquery-pjax . The actual effect is as follows: http://pjax.heroku.com / When pjax is not checked, clicking on a link is a jump. When checked, the links become ajax refreshes.
Why use pjax?
pjax has several advantages:
-
User experience improvement.
When the page jumps, the human eye needs to re-recognize the whole page. When refreshing part of the page, only one area needs to be re-identified. Since I was on my website. GuruDigger After using pjax technology above, I can't help feeling that visiting other websites that only have page jumps is a lot of pain. At the same time, users can tolerate longer page loading times because of the loading hint provided when refreshing part of the page and the fact that the old page is still displayed in the browser when refreshing.
-
It greatly reduces bandwidth consumption and server consumption.
Most requests (css/js) will not be retrieved because only part of the page is refreshed. The outer frame of the website with user login information does not need to be regenerated. Although I haven't specifically counted the consumption of this part, I estimate that at least 40% of requests and 30% of server consumption have been saved.
The disadvantages, I think, are as follows:
-
Support of IE6 and other historical browsers
Although I haven't actually tested it, the compatibility of old browsers is problematic because pjax takes advantage of new standards. But pjax itself supports fallback, and when it finds out that browsers don't support it, it goes back to the original page jump.
-
Complex server-side support
The server side needs to decide whether to render the whole page or part of the page according to the request from the server side, which makes the system more complex. However, for well-designed server code, support for such functions will not be too much of a problem.
How to use pjax?
Look directly. Official documents That's all. I think people who are technicians should develop the habit of looking at first-hand technical data. There is a rails for pjax. gem plug-in It can be used directly. Also have django support .
Principle of pjax
To be able to handle problems, we need to be able to understand how pjax works. The code for pjax has only one file: https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js If you have the ability, you can go and see it for yourself. I'll explain the principle here. First, we specify in html what links to pjax need to be made, and what parts need to be updated after clicking (in the data-pjax attribute):
$('a[data-pjax]').pjax()
When the pjax script is loaded, it intercepts the events of these links, then wraps them up as an ajax request and sends them to the server.
$.fn.pjax = function( container, options ) {
return this.live('click.pjax', function(event){
handleClick(event, container, options)
})
}
function handleClick(event, container, options) {
$.pjax($.extend({}, defaults, options))
...
event.preventDefault()
}
var pjax = $.pjax = function( options ) {
...
pjax.xhr = $.ajax(options)
}
This request has the HEADER ID of X-PJAX. When the server receives such a request, it knows that it only needs to render part of the page to return.
xhr.setRequestHeader('X-PJAX', 'true')
xhr.setRequestHeader('X-PJAX-Container', context.selector)
When pjax receives the returned request, it updates the area specified by data-pjax, as well as the address of the browser.
options.success = function(data, status, xhr) {
var container = extractContainer(data, xhr, options)
...
if (container.title) document.title = container.title
context.html(container.contents)
}
In order to support browser retrogression, the api of history is used to record the corresponding information.
pjax.state = {
id: options.id || uniqueId(),
url: container.url,
container: context.selector,
fragment: options.fragment,
timeout: options.timeout
}
if (options.push || options.replace) {
window.history.replaceState(pjax.state, container.title, container.url)
}
When the browser retreats, it intercepts events and generates a new ajax request based on recorded historical information.
$(window).bind('popstate', function(event){
var state = event.state
if (state && state.container) {
var container = $(state.container)
if (container.length) {
...
var options = {
id: state.id,
url: state.url,
container: container,
push: false,
fragment: state.fragment,
timeout: state.timeout,
scrollTo: false
}
if (contents) {
// pjax event is deprecated
$(document).trigger('pjax', [null, options])
container.trigger('pjax:start', [null, options])
// end.pjax event is deprecated
container.trigger('start.pjax', [null, options])
container.html(contents)
pjax.state = state
container.trigger('pjax:end', [null, options])
// end.pjax event is deprecated
container.trigger('end.pjax', [null, options])
} else {
$.pjax(options)
}
...
}
}
}
To support fallback, one is to determine whether the browser supports history push state API when loading:
// Is pjax supported by this browser?
$.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]|WebApps\/.+CFNetwork)/)
The other is to do page jumps directly when you find that the request has not been answered for a period of time (you can set the parameter timeout).
options.beforeSend = function(xhr, settings) {
if (settings.timeout > 0) {
timeoutTimer = setTimeout(function() {
if (fire('pjax:timeout', [xhr, options]))
xhr.abort('timeout')
}, settings.timeout)
// Clear timeout setting so jquerys internal timeout isn't invoked
settings.timeout = 0