嘛,起因是黑子大叔在微博上的一条@信息,找起了这个的实现,看了一圈google的中文信息内似乎还没有怎么提到这个的内容,就发表上来。
详细效果就是类似于用Firefox4+/Chrome 5+/Safari 5+/Opera 11.5+登录新浪微博后看到的个人时间轴,在翻页时可以观察到这个效果,地址栏URL变动,但是页面没有刷新,用firebug观察也观察不到刷新整个页面,只有ajax请求的翻页数据。从先前的理解来说,URL的修改必然引起(请注意我不是在说通过锚点修改)浏览器重载页面,但利用HTML5新加入的history.pushState();和history.replaceState();可以完全自己维护一个历史记录列表绕开历史记录完全由浏览器控制的机制,从而实现比锚点更加完美的一种页内更新的体验。
代码方面很简单,只要在需要修改url的地方插入一行:
window.history.pushState({"html":response.html,"pageTitle":response.pageTitle}, ‘title‘, urlPath); //三个参数,分别为:状态对象,标题(目前被浏览器忽略),地址 |
即可在历史记录里面产生一个新的历史记录(另一个replaceState方法参数完全相同,只是替代掉当前的状态)。
在体验上,非常接近于使用锚点(window.location = “#foo”;),但是mozilla的文档提出了以下三点好处:
- 新的URL可以是和原始页面URL同域下的任何URL,如果用锚点,只能更新#后面的部分
- 仅在需要时更新URL,锚点的历史记录在相同时不会创建(即当前已经是”#foo”的情况下,如果再将当前页面锚点设置为”#foo”,不会产生新的历史记录)
- 可以记录下任意类型的数据,使用锚点的话将要自己维护一份历史数据列表或者把数据转码到一个字符串里
(翻译&描述的有点别扭,见笑了,不过其实应该自己也能体会到这些好处才是)
我自己实现的一个例子:
http://vifix.cn/atelier/demos/html5-update-browser-url-without-reloading-page
代码:
<?php if(!isset($_REQUEST[‘page‘])){ $page = 1; } else{ $page = intval($_REQUEST[‘page‘]); } if(isset($_REQUEST[‘ajaxload‘])){ echo "第{$page}页的内容"; die; } ?> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>HTML5 修改浏览器url而不刷新页面</title> <script type="text/javascript"> var domLoaded = function(){ if(ua != null && ua[1] < 10){ alert(‘您的浏览器不支持‘); return ; } if(location.href.indexOf("?") > -1){ var urlparts = location.href.match(/(.+?)\?.+/i); var urlbase = urlparts[1]; } else{ var urlbase = location.href; } var page = <?php echo $page;?>; var ua = window.navigator.userAgent.match(/msie (\d\.\d)/i); var content = document.getElementById("content"); var loading = document.getElementById("loading"); window.history.replaceState( { content:content.innerHTML, page:page }, page, urlbase + (page > 1 ? ‘?page=‘ + page : ‘‘ ) ); var ajax = new XMLHttpRequest(); var ajaxCallback = function(){ if(ajax.readyState == 4){ loading.style.display = ‘none‘; content.innerHTML = ajax.responseText; window.history.pushState( { content:content.innerHTML, page:page }, page, urlbase + "?page=" + page ); next.href = urlbase + "?page=" + (page + 1); } }; var next = document.getElementById(‘next‘); var nextClickEvent = function(event){ if(loading.style.display != ‘block‘){ loading.style.display = ‘block‘; page++; ajax.open(‘GET‘, urlbase + ‘?page=‘ + page + ‘&ajaxload=on‘, true); ajax.onreadystatechange = ajaxCallback; ajax.send(‘‘); event.preventDefault(); } }; next.addEventListener(‘click‘, nextClickEvent, false); var popstate = function(){ content.innerHTML = history.state.content; page = history.state.page; }; window.addEventListener(‘popstate‘, popstate, false); }; try{ window.addEventListener(‘DOMContentLoaded‘, domLoaded, false); } catch(e){ alert(‘您的浏览器不支持‘); } </script> </head> <body> <p id="content"> <?php echo "第{$page}页的内容";?> </p> <p> <a id="next" href="?page=<?php echo $page+1;?>">下一页</a> </p> <div id="loading" style="display:none;"> 加载中 </div> </body> </html> |
mozilla的文档
https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history
stackoverflow上的相关问题:
http://stackoverflow.com/questions/3338642/updating-address-bar-with-new-url-without-hash-or-reloading-the-page
http://stackoverflow.com/questions/824349/modify-the-url-without-reloading-the-page
http://vifix.cn/blog/html5-modify-browser-url-without-reloading-page.html