pjax 笔记

PJAX的基本思路是,用户点击一个链接,通过ajax更新页面变化的部分,然后使用HTML5的pushState修改浏览器的URL地址,这样有效地避免了整个页面的重新加载。如果浏览器不支持history的两个新API或者JS被禁用了,那这个链接就只能跳转并重新刷新整个页面了。和传统的ajax设计稍微不同,ajax通常是从后台获取JSON数据,然后由前端解析渲染,而PJAX请求的是一个在服务器上生成好的HTML碎片.

客户端向服务器发送一个普通的请求(1),其实也就是点击了一个链接,服务器会相应这个请求(2),返回一个html文档。客户端向服务器发送一个有PJAX标志的请求(3),此时服务器只返回一个html碎片(4)。但是这两次请求都让客户端的URL变化了,希望上面的说明可以让你明白了PAJX和AJAX的区别了。

 

用法

  1. 引入jquery和jquery.pjax.js
  2. 注册事件
    /**
     * 方式一 按钮父节点监听事件
     *
     * @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');

 

options默认参数说明

参数名默认值说明
timeout 650 ajax 超时时间(单位ms),超时后会执行默认的页面跳转,所以超时时间不应过短,不过一般不需要设置
push true 使用window.history.pushState改变地址栏url(会添加新的历史记录)
replace false 使用window.history.replaceState改变地址栏url(不会添加历史记录)
maxCacheLength 20 缓存的历史页面个数(pjax加载新页面前会把原页面的内容缓存起来,缓存加载后其中的脚本会再次执行)
version   是一个函数,返回当前页面的pjax-version,即页面中<meta http-equiv="x-pjax-version">标签内容。使用response.setHeader("X-PJAX-Version", "")设置与当前页面不同的版本号,可强制页面跳转而不是局部刷新。
scrollTo 0 页面加载后垂直滚动距离(与原页面保持一致可使过度效果更平滑)
type "GET" ajax的参数,http请求方式
dataType "html" ajax的参数,响应内容的Content-Type
container   用于查找容器的CSS选择器,[container]参数没有指定时使用
url link.href 要跳转的连接,默认a标签的href属性
target link pjax事件参数e的relatedTarget属性,默认为点击的a标签
fragment   使用响应内容的指定部分(css选择器)填充页面,服务端不进行处理导致全页面请求的时候需要使用该参数,简单的说就是对请求到的页面做截取

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参数

 
实际操作中出现问题: 
pajx在浏览器回退和前进是无任何问题的。但如果你进行刷新或F5操作。那么加载出来的页面仅仅为地址栏后台请求出来的页面:比如,如果你的菜单栏项是通过pjax(这里请求的页面dom为 a/list.html)加载对应的内容到指定div(这里假设为div1)。那么如果进行了刷新或F5操作后页面出现的仅仅为 a/list.html页面的布局和信息。如何解决? 
pajx在提交的头信息中包括了 x-pjax: true

  • 1.服务器端判断是否为x-pjax请求

    服务器后台可通过该字段来判断是否为x-pjax请求。或者自己定义好参数传到后台来区分是否是x-pjax的请求。

  • 2.如果不为x-pjax请求则转发到首页地址

    如果你菜单项的首页为index.html 则转发到该页面。那么在刷新后就能够跳转到首页。包含了菜单项等。

@Controller
public class TestController {
    
    @RequestMapping("/")
    public String index(){
        return "index";
    }
    
    @RequestMapping("/data")
    public String test(HttpServletRequest request){
        boolean b = Boolean.valueOf(request.getHeader("x-pjax"));
        if(b){
            
        }else{
            return "redirect:/";
        }
        return "test";
    }

}

 

 
posted @ 2017-09-30 01:07  Kindi丶  阅读(488)  评论(0编辑  收藏  举报