什么是pjax?

现在很多网站( facebook, twitter)都支持这样的一种浏览方式, 当你点击一个站内的链接的时候, 不是做页面跳转, 而是只是站内页面刷新。 这样的用户体验, 比起整个页面都闪一下来说, 好很多。 其中有一个很重要的组成部分, 这些网站的ajax刷新是支持浏览器历史的, 刷新页面的同时, 浏览器地址栏位上面的地址也是会更改, 用浏览器的回退功能也能够回退到上一个页面。 那么如果我们想要实现这样的功能, 我们如何做呢? 我发现pjax提供了一个脚本支持这样的功能。 pjax项目地址在 https://github.com/defunkt/jquery-pjax 。

为什么要用pjax?

pjax有好几个好处:

  • 用户体验提升。
    页面跳转的时候人眼需要对整个页面作重新识别, 刷新部分页面的时候, 只需要重新识别其中一块区域。 同时, 由于刷新部分页面的时候提供了一个loading的提示, 以及在刷新的时候旧页面还是显示在浏览器中, 用户能够容忍更长的页面加载时间。
  • 极大地减少带宽消耗和服务器消耗。
    由于只是刷新部分页面, 大部分的请求(css/js)都不会重新获取, 网站带有用户登录信息的外框部分都不需要重新生成了。

如何使用pjax?

  • 引入jquery和jquery.pjax.js
  • 注册事件
/*** 方式一 按钮父节点监听事件** @param selector  触发点击事件的按钮* @param container 展示刷新内容的容器,也就是会被替换的部分* @param options   参数*/
$(document).pjax(selector, [container], options);
// 方式二 直接对按钮监听,可以不用指定容器,使用按钮的data-pjax属性值查找容器
$("a[data-pjax]").pjax();
// 方式三 常规的点击事件监听方式
$(document).on('click', 'a', $.pjax.click);
$(document).on('click', 'a', function(event) {var container = $(this).closest('[data-pjax-container]');$.pjax.click(event, container);
});
// 下列是源码中介绍的其他用法,
// 表单提交
$(document).on('submit', 'form', function(event) {var container = $(this).closest('[data-pjax-container]');$.pjax.submit(event, container);
});
// 加载内容到指定容器
$.pjax({ url: this.href, container: '#main' });
// 重新当前页面容器的内容
$.pjax.reload('#container');

具体文档详见:https://github.com/defunkt/jquery-pjax

pjax的原理

为了能够处理问题, 我们需要能够理解pjax的运作方式。 pjax的代码只有一个文件: https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js 如果有能力, 可以自己去看一遍。 我这里解释一下原理。 首先, 我们在html里面指定, 需要做pjax的链接内容是哪些, 以及点击之后需要更新的部分(放在data-pjax属性里面):

$('a[data-pjax]').pjax()

当加载了pjax脚本之后, 它会拦截这些链接的事件, 然后包装成一个ajax请求, 发送给服务器。

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

这个请求带有X-PJAX的HEADER标识, 服务器在收到这样的请求的时候, 就知道只需要渲染部分页面返回就可以了。

xhr.setRequestHeader('X-PJAX', 'true')
xhr.setRequestHeader('X-PJAX-Container', context.selector)

pjax接受到返回的请求之后, 更新data-pjax指定的区域, 同时也会更新浏览器的地址。

options.success = function(data, status, xhr) {var container = extractContainer(data, xhr, options)...if (container.title) document.title = container.titlecontext.html(container.contents)
}

为了能够支持浏览器的后退, 利用到了history的api, 记录下来对应的信息,

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

当浏览器后退的时候, 拦截事件, 根据记录的历史信息, 产生一个新的ajax请求。

$(window).bind('popstate', function(event){var state = event.stateif (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 deprecatedcontainer.trigger('start.pjax', [null, options])container.html(contents)pjax.state = statecontainer.trigger('pjax:end', [null, options])// end.pjax event is deprecatedcontainer.trigger('end.pjax', [null, options])} else {$.pjax(options)}...}}
}

为了支持fallback, 一个是在加载的时候判断浏览器是否支持history push state API:

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

另一个是当发现请求一段时间没有回复的时候(可以设置参数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 invokedsettings.timeout = 0

pjax失效情况

会有一些情况导致pjax失效,下面结合源码分析下(省略部分无关代码)

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(在Windows键盘中是Windows键,在苹果机中是Cmd键)// 作用分别代表新窗口打开、新标签打开(不切换标签)、下载、新标签打开(切换标签)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. 已经阻止元素发生默认的行为(url跳转)if (event.isDefaultPrevented())return...var clickEvent = $.Event('pjax:click')$(link).trigger(clickEvent, [opts])// 6. pjax:click事件回调中已经阻止元素发生默认的行为(url跳转)if (!clickEvent.isDefaultPrevented()) {pjax(opts)event.preventDefault()// 阻止url跳转$(link).trigger('pjax:clicked', [opts])}
}

除了上述情况之外,还有下列几种情况:

  • ajax请求失败,或者timeout后请求被中止
  • 当前页面X-PJAX-Version和请求的新页面版本不一致
  • 请求得到完整的页面(包含html标签)却没设置fragment参数

Demo

index.php

<!DOCTYPE html>
<html>
<head><title>pjax</title><meta charset="utf-8">
</head>
<body>
<h1>My Site</h1>
<div>Go to <a href="res1.php">第一页</a>.<a href="res2.php">第二页</a>
</div>
<div id="container"></div>
</body>
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="jquery.pjax.js"></script>
<script type="text/javascript">$(document).pjax('a', '#container')
</script>
</html>

res1.php

<?php
echo "<div style='background:red;'>第一页</div>";

res2.php

<?php
echo "<div style='background:red;'>第二页</div>";

效果:

Demo2

index.html

<!DOCTYPE html>
<html>
<head><title>pjax</title><meta charset="utf-8">
</head>
<body><h1>My Site</h1><div><input type="button" id="th" value="GO"></div><div id="container"></div>
</body>
<script src="../jquery-2.1.4.min.js"></script>
<script src="../jquery.pjax.js"></script>
<script type="text/javascript">
$(function(){$('#th').click(function(){$.pjax({url: './res3.php',container: '#container'});});
});
</script>
</html>

re3.php

<?php
echo "<div style='background:red;'>第三页</div>";

【Jquery】Pjax的了解与应用相关推荐

  1. jQuery+pjax简单示例汇总

    pjax 是一个jQuery插件,它使用 ajax 和 pushState 来实现快速的浏览体验,包括真正的固定链接,页面标题和工作返回按钮. ajax缺点是破坏了浏览器的前进后退,因为ajax的请求 ...

  2. php pjax案例,基于jquery.pjax实现Pjax效果详解

    pjax是对ajax + pushState的封装,ajax大家应该都明白,就是使用xmlhttprequest对象与服务端进行交换数据,pushState是一个可以操作history的api.说白了 ...

  3. php pjax案例,jQuery pjax简单示例汇总

    pjax 是一个jQuery插件,它使用 ajax 和 pushState 来实现快速的浏览体验,包括真正的固定链接,页面标题和工作返回按钮.本文主要和大家分享jQuery pjax简单示例汇总,希望 ...

  4. pjax php demo,jQuery pjax 应用简单示例

    pjax 是一个jQuery插件,它使用 ajax 和 pushState 来实现快速的浏览体验,包括真正的固定链接,页面标题和工作返回按钮. ajax缺点是破坏了浏览器的前进后退,因为ajax的请求 ...

  5. jQuery Pjax于ajax的区别

    最近小松发现了Pjax的技术,本来想把这个用到自己的博客上,相信还是算了吧,之后找个时间在搞 ajax ajax技术应该大家都知道就是用来后台与服务器进行少量数据交换,也就不用刷新页面就能看到数据内容 ...

  6. pjax 历史管理 jQuery.History.js

    更新 http://www.bootcdn.cn/jquery.pjax/ 简介 pjax是一个jQuery插件,使用ajax和pushState技术提供快速的浏览体验与真正的永久链接.网页标题.以及 ...

  7. java pjax_通过pjax实现无刷新翻页(兼容新版jquery)

    摘要:这篇jQuery栏目下的"通过pjax实现无刷新翻页(兼容新版jquery)",介绍的技术点是"jQuery.无刷新翻页.pjax.无刷新.刷新.翻页", ...

  8. Pjax是什么以及为什么推荐大家用

    什么是pjax? 现在很多网站( facebook,  twitter) 都支持这样的一种浏览方式, 当你点击一个站内的链接的时候, 不是做页面跳转, 而是只是站内页面刷新. 这样的用户体验, 比起整 ...

  9. Typecho开启全站Pjax

    原文地址:Typecho开启全站Pjax 前言 因为上次更新后加入民音乐插件,但是有个问题就是在页面跳转的时候由于页面已经刷新了,所以音乐就不会继续播放了,就想着去引入Pjax来解决这个问题,同时引入 ...

最新文章

  1. 【部署类】专题:消息队列MQ、进程守护Supervisor
  2. 入职五年回顾(八) 2013年3月
  3. 开发文件上传功能稍不注意就会引发安全漏洞
  4. PPP、MP 和 SLIP 配置(上)
  5. UVA10047独轮车
  6. linux或者shell进入vi命令
  7. SAP Spartacus breakpoint服务中platformID的注入逻辑
  8. 对比linux终端模式和图形模式,Linux知识-2. Linux初学(CnetOS Linux7)之切换命令模式和图形模式...
  9. java的handleback类,CallbackHandler
  10. 设计模式原则之六:依赖倒置原则
  11. QObject: Cannot create children for a parent that is in a different thread.
  12. 为什么现在的程序员那么卑微?青出于蓝而胜于蓝啊
  13. GO语言实现区块链Part6 Transactions 2
  14. 第二章 查询结果排序(SQL server经典实例)
  15. 双目视觉(三)立体匹配算法
  16. 极客日报第89期:经纬张颖「炮轰」扫码点餐;淘宝特价版给拼多多送芒果;Firefox 87.0 发布
  17. Goland嗖嗖的: 快捷键,自动生成代码等效率小技巧
  18. Harris角点特征提取和角点特征匹配(2)
  19. 和讯网分行业和分省份社会责任指数(2010-2020年)
  20. 基于阿里云容器镜像服务加速K8S镜像下载(二)

热门文章

  1. 计算机网络中常见的各层协议
  2. 海信a5,掌阅f1手机水墨屏护眼日常使用经验
  3. Convolutional Neural Network
  4. centos安装git(centos安装vmware tools)
  5. Word count通过mr实现China的编程
  6. Redis五大数据类型及常见命令
  7. VisualBasic使用CDO发送SSL加密邮件【我TM还是太年轻了】
  8. 窗函数(window function)
  9. Surciata源码分析之IpsNFQ模式(1)
  10. 正交采样 matlab,MATLAB数值积分(正交)