实现不刷新整个页面进行前进后退

来源:互联网 发布:淘宝高颜值平价零食 编辑:程序博客网 时间:2024/05/21 17:11
在html5出来前,实现无刷新前进后退通常是结合location.hash+onhashchange事件来实现的;
在html5出来后,可以使用h5 history api来实现无刷新前进后退

点击浏览器的前进后退按钮时,只要将要进入的页面与当前页面不是同一个页面(因为有可能人为地添加了一条历史记录,但实际上还是同一个页面),那么将要进入的页面其所有请求(包括html、js、css、json和图片等)都是直接从缓存里读取的(除非禁用了缓存),但js还是会重新执行一遍。如果该页面是用ajax获取数据的,那么不管前进或者后退到该页面时,都会重新ajax请求数据。


HTML5中history那些事
SEPTEMBER 26TH, 2015
HTML5中History对象提供了两个新的方法,pushState和replaceState用来在无刷新页面情况下更改url,为单页应用提供了很大方便,但是在使用时需要注意一些事情。

原来有什么
History对象原来有三个方法,一个属性。

history.length:历史列表中的网址数。
history.back():加载历史列表前一个网址。
history.forward():加载历史列表后一个网址。
history.go(num):加载历史列表中的某个页面,参数为相对当前页面,跳转的次数。go(-1)与back()效果相同,go(1)与forward()效果相同。go(-2)与单击两次后退按钮执行的操作一样。
新增了什么
History对象新增了两个方法,一个属性,新增了一个事件。

history.pushState(state,title,url):替换url为当前url并添加历史记录,title为历史记录的title,state为一个用户存储的对象,可以通过history.state或window.onpopstate事件的event.state访问。
history.replaceState(state,title,url):参数与history.pushState相同,不同点在于该方法更改当前历史记录,不会产生新的历史记录。
history.state:用户存储的对象。
window.onpopstate:当使用history.pushState或history.replaceState控制历史记录后,触发浏览器的前进/回退操作会触发该事件。
注意事项
state属性不能通过history.state或window.onpopstate的event.state来修改,只能通过history.pushState或history.replaceState修改。
state属性必须是可序列化的值,如DOM对象不可设置。
history.state与window.onpopstate的event.state不相等。
history.pushState与history.replaceState的url参数与网站url必须是同域的,否则会出现跨域错误。需要注意,当history.pushState或history.replaceState的url参数为/abc/def或abc/def时所使用的origin为加载该<script>的origin,如果操作History的是外部js文件,请拼接上location.origin。

还差什么
当前在哪
History没有提供获取当前页面在历史列表位置的方法,这个属性作用不大,只有在单页应用,且拥有非顺序跳转逻辑时才会用到,既然系统不提供,只能自己推算。
首先要保证每个页面设置state属性,这样可以通过该属性判断是否是已经加载过页面。 当首次加载应用时,检查history.state属性,如果该属性未设置,那么必然为新开页面,此时必然为历史列表第一个,当使用history.pushState后,逻辑同上。,此两种情况current为history.length。其余情况即为页面跳转或当前页面刷新,current即为之之前两种情况保存的值。


HTML4中的History API
属性
length 历史的项数。javascript 所能管到的历史被限制在用浏览器的“前进”“后退”键可以去到的范围。本属性返回的是“前进”和“后退”两个按键之下包含的地址数的和。
方法
back() 后退,跟按下“后退”键是等效的。
forward() 前进,跟按下“前进”键是等效的。
go() 用法:history.go(x);在历史的范围内去到指定的一个地址。如果 x < 0,则后退 x 个地址,如果 x > 0,则前进 x 个地址,如果 x == 0,则刷新现在打开的网页。history.go(0) 跟 location.reload() 是等效的。

HTML5中的History API(使用h5的history api可以不用更改页面url的hash值)

操纵浏览器的历史记录
  1. history.pushState(data, title [, url]):往历史记录堆栈顶部添加一条记录;data会在onpopstate事件触发时作为参数传递过去;title为页面标题,当前所有浏览器都会 忽略此参数;url为页面地址,可选,缺省为当前页地址。
  2. history.replaceState(data, title [, url]) :更改当前的历史记录,参数同上。
  3. history.state:获取历史栈中最顶端的state数据(即history.pushState中的第一个参数),不同浏览器的读写权限不一样。
  4. popstate事件:当用户单击浏览器的后退或者前进按钮(或者调用history.go,history.back,history.forward方法也会触发popstate事件。调用history.pushState()或者history.replaceState()不会触发popstate事件,但改变url中的hash值会触发popstate事件)时触发该事件。在事件处理函数中读取触发事件的事件对象的state属性值,该属性值即为执行pushState方法时所使用的第一个参数值,该state与history.state是相同的,而不是历史栈中被抛出的state对象。
到目前为止,IE10,firefox4以上的版本,Chrome8以上的版本,Safari5,Opera11以上的版本浏览器支持HTML5中的History API。

判断是否支持h5 history api:
if ('pushState' in history) { ... };

h5 history api实现无刷新跳转

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!DOCTYPE html>
<html lang="en">
<!-- saved from url=(0014)about:internet -->
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<a href="">change color</a>
<p style="cursor:pointer;text-decoration:underline;">other color</p>
<div style="height: 100px;background-color: red;"></div>
<script>
    history.replaceState({
        color: 'red'
    }, '红色''red.html');
    window.onpopstate = function (event) {
        setBackgroundColor(event.state.color);
    };
    document.getElementsByTagName('a')[0].onclick = function (event) {
        event.preventDefault();
        if (history.state.color === 'red') {   //上一次为红色
            setBackgroundColor('green');
            history.pushState({
                color: 'green'
            }, '绿色''green.html');
        else if (history.state.color === 'green' || history.state.color === 'yellow') {  //上一次为绿色或黄色
            setBackgroundColor('blue');
            history.pushState({
                color: 'blue'
            }, '蓝色''blue.html');
        }
    };
document.getElementsByTagName('p')[0].onclick=function(event){
   if (history.state.color !== 'yellow') {   //如果当前页不是黄色
setBackgroundColor('yellow');
            history.pushState({
                color: 'yellow'
            }, '黄色''yellow.html');   
}
}
    function setBackgroundColor(color) {
        document.getElementsByTagName('div')[0].style.backgroundColor = color;
    }
</script>
</body>
</html>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>history 测试</title>
</head>
<body>
     
    <p><input type="text" value="0" id="oTxt" /></p>
    <p><input type="button" value="+"  id="oBtn" /></p>
 
    <script>
 
    var otxt = document.getElementById("oTxt");
    var oBtn = document.getElementById("oBtn");
    var n = 0;
 
    oBtn.addEventListener("click",function(){
        n++;
        add();
    },false)
    get();
 
    function add(){
        if("pushState" in history){
            otxt.value=n;
            history.pushState({num:n},null,location.href.split("?")[0]+"?num="+n);
        }
    }
    function get(){
        if("onpopstate" in window){
            window.addEventListener("popstate",function(e){
                alert('popstate事件');
                if(e.state && e.state.num){
                    n = e.state.num;
                }else{
                    n=0;
                }
                otxt.value = n;
            },false);
        }
    }
     
    </script>
</body>
</html>

使用location.hash+onhashchange实现无刷新跳转

原理:改变url中#后面的值会创建一条历史记录(但不会刷新整个页面)并会触发onhashchange事件。监听此事件并通过window.location.hash获取url中 "#val" 的值。根据不同的"#val" 来触发页面不同的操作,显示对应内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>history 测试</title>
</head>
<body>
 
<p><input type="text" value="0" id="oTxt" /></p>
<p><input type="button" value="+"  id="oBtn" /></p>
 
<script>
    var otxt = document.getElementById("oTxt");
    var oBtn = document.getElementById("oBtn");
    var n = 0;
 
    oBtn.addEventListener("click",function(){
        n++;
        add();
    },false);
    get();
 
    function add(){
        if("onhashchange" in window){
            window.location.hash = "#"+n;
        }
    }
 
    function get(){
        if("onhashchange" in window){
            window.addEventListener("hashchange",function(e){
                var hashVal = window.location.hash.substring(1);
                if(hashVal){
                    n = hashVal;
                }else{
                    n=0;
                }
                otxt.value = n;
            },false);
        }
    }
</script>
</body>
</html>


JS刷新页面

1,reload 方法,该方法强迫浏览器刷新当前页面。
语法:location.reload([bForceGet])   
参数: bForceGet, 可选参数, 默认为 false,从客户端缓存里取当前页。true, 则以 GET 方式,从服务端取最新的页面, 相当于客户端点击 F5("刷新")

2,replace 方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,你不能通过“前进”和“后退”来访问已经被替换的URL。
语法: location.replace(URL)   
通常使用: location.reload() 或者是 history.go(0) 来做。
此方法类似客户端点F5刷新页面,所以页面method="post"时,会出现"网页过期"的提示。
因为Session的安全保护机制。
当调用 location.reload() 方法时, aspx页面此时在服务端内存里已经存在, 因此必定是 IsPostback 的。
如果有这种应用: 需要重新加载该页面,也就是说期望页面能够在服务端重新被创建,期望是 Not IsPostback 的。
这里,location.replace() 就可以完成此任务。被replace的页面每次都在服务端重新生成。
代码: location.replace(location.href);

返回并刷新页面:
location.replace(document.referrer);
document.referrer //打开当前页面的文档的URL
这种方法并不是返回到上一个历史记录,而是将当前的记录替换为document.referrer,导致history中有重复的两个document.referrer记录
不要用 history.go(-1),或 history.back();来返回并刷新页面,这两种方法不会刷新页面,而是直接从浏览器缓存里获取内容(除非禁用了缓存)。


Javascript刷新页面(即重新从服务器下载页面)的几种方法:


F5和CTRL+F5的区别
以下都是在chrome下测试的

1,history.go(0) 
跟按F5一样,无法跳过浏览器缓存。F5触发的所有HTTP请求的请求头中通常包含了If-Modified-Since 或 If-None-Match字段,或者两者兼有.如果服务器认为被请求的文件没有发生变化,则返回304响应,浏览器直接从缓存中获取.
注意点:上述情况只适用于第一次请求时响应头中携带Last-Modified或者ETag字段的请求,如果第一次请求时响应头中没有携带这些字段,而是携带的Transfer-Encoding:chunked(分块传输),那么再次发起该请求时,请求头里不会携带If-Modified-Since 或 If-None-Match字段,会从服务器重新下载文件

CTRL+F5触发的HTTP请求的请求头中没有上面的那两个头(所有的请求都是从服务器重新获取数据),却有Pragma: no-cache 或 Cache-Control: no-cache 字段,或者两者兼有.服务器看到no-cache这样的值就会把最新的文件响应过去.也就跳过了缓存.

2,location.reload() 
3,location=location 
4,location.assign(location) 
5,document.execCommand('Refresh') 
6,window.navigate(location) 
7,location.replace(location) 

8,document.URL=location.href


来源网址:http://www.qdfuns.com/notes/17631/ff37e5968e6592847e05c14ce754c917.html