分类 HTML+CSS+JS 下的文章

pushState方法实例与PJAX

平时没有注意过,其实推特的网站用了很多HTML5的新技术。
每次点击链接的时候,页面并不是全部刷新的,而是像AJAX那样,局部刷新的。
如果单独使用AJAX,无论局部刷新多少次,只要用户一后退,页面变化的历史就都没了。
而这里和AJAX不同的是,当点击浏览器上的后退按钮时,页面会回到上一个局部刷新时的状态。
这里用到了HTML5的一个新特性,history对象的pushState、replaceState相关操作。
这种结合了AJAX、pushState的技术,简称为PJAX

使用pushState应用的设计

最简单的一种应用,就是保存当前网页的状态。
比如用户点开了网页上的一个面板,这个过程并不需要向服务器发送请求,只需要用户后退的时候关闭面板就好。
这种时候,只要在网页加载完成时替换一个初始状态,用户打开面板时压入一个状态,在用户后退时回到初始状态即可。
推特之类的网站就是结合了AJAX使用的pushState方法。
用户点击链接的时候,将URL压入历史纪录,这样地址栏里的内容就变成了新页面的URL。
然后使用AJAX,带上特殊的请求头,向服务器请求页面数据,如此就不需要请求整个页面了。
用户后退的时候,根据历史纪录里的URL,使用AJAX重新加载局部数据即可。服务端可根据这个请求头判断,是返回完整的网页还是网页部分数据。
也可以将AJAX请求到的数据放在localStorage中,后退时直接调取而不是重新请求。

pushState实际应用

这里用一个+1程序作为例子
首先写一个数字+1的方法

//喜加一
addone = function(){
    //模拟页面数据改变
    value = parseInt(document.getElementById('display').innerHTML);
    value = value+1;
    //压入历史纪录
    history.pushState({v:value},value+'','?count='+value);
    //pushState并不会触发onpopstate回调
    //手动调用来触发加载数据的动作
    window.onpopstate();
}

pushState方法有三个参数:
第一个参数是一个自定义对象,之后可以使用history.state获取
第二个参数是状态名称
第三个参数是URL地址,用于浏览器地址栏的显示,可以通过windows.location获取
然后完成onpopstate回调,实现加载数据以及更新页面:

window.onpopstate = function(){
    //这里的data对象就是pushState传入的第一个对象,只读
    data = history.state;
    //可以用ajax加载数据了
    url = window.location.toString();
    //......
    //加载完之后更新页面
    document.getElementById('display').innerHTML = data.v + '';
    //AJAX是异步加载的,更新页面之前最好检查一下location
}

页面写到这里会有一个问题,就是在退回初始状态时,history.state对象未定义,所以要给页面一个初始历史:

history.replaceState({v:0},'0','?count=0');
//手动调用来触发加载数据的动作
window.onpopstate();

这样就实现了一个点击+1的页面,后退的话就会"-1",完整的页面代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>历史纪录测试</title>
</head>
<body>
    <script>
        //当后退或前进时触发事件
        window.onpopstate = function(){
            //这里的data对象就是pushState传入的第一个对象,只读
            data = history.state;
            //可以用ajax加载数据了
            url = window.location.toString();
            //......
            //加载完之后更新页面
            document.getElementById('display').innerHTML = data.v + '';
            //AJAX是异步加载的,更新页面之前最好检查一下location
        }
        //喜加一
        addone = function(){
            //模拟页面数据改变
            value = parseInt(document.getElementById('display').innerHTML);
            value = value+1;
            //压入历史纪录
            history.pushState({v:value},value+'','?count='+value);
            //pushState并不会触发onpopstate回调
            //手动调用来触发加载数据的动作
            window.onpopstate();
        }
        //初始化历史纪录栈
        history.replaceState({v:0},'0','?count=0');
        //手动调用来触发加载数据的动作
        window.onpopstate();
    </script>
    <button onclick="addone();">喜加一</button>
    <pre id="display">0</pre>
</body>
</html>

全剧终