引入history.pushState的来龙去脉

大家都知道web2.0以来,大家都喜欢使用ajax来请求数据,提高用户体验,但是传统的ajax可以无刷新改变页面内容,但无法改变页面URL,无刷新的改变页面内容而url没有改变导致搜索引擎无法抓取改变的页面内容。

为了提高可访问性,大家想了各种方法,比如说改变URL的hash,但是hash的方式不能很好的处理浏览器的前进、后退,为了能够区分不同的hash,浏览器引入了onhashchange事件,但并在所有浏览器都支持onhashchange,对于不支持onhashchange事件的浏览器只能通过定时去判断hash是否改变,而且搜索引擎不会理会井号,因此也就无法索引内容,这种方式显然不够灵活。

为此twitter和google约定了使用#!xxx(即hash第一个字符为!),引用了新的方式#!之后搜索引擎必须加以支持,比如说网址是http://example.com#!1,当搜索引擎发现上述网址是会自动解析成http://example.com?_escaped_fragment_=1,但是这种方式对用户来说使用起来相当麻烦。

这时HTML5为了解决传统ajax带来的问题引入了新的API,即:history.pushState, history.replaceState

history.pushState

pushState是将指定的URL添加到浏览器历史里,存储当前历史记录点

API:history.pushState(state, title, url)

  1. // @state状态对象:记录历史记录点的额外对象,可以为空
  2. // @title页面标题:目前所有浏览器都不支持
  3. // @url可选的url:浏览器不会检查url是否存在,只改变url,url必须同域,不能跨域

history.pushState的目的

  • SEO优化
  • 更少的数据请求
  • 更好的用户体验

history.replaceState

replaceState是将指定的URL替换当前的URL,替换当前历史记录点

replaceState的api和pushState类似,不同之处在于replaceState不会在window.history里新增历史记录点,而pushState会在历史记录点里新增一个记录点的

history.state

当前URL下对应的状态信息。如果当前URL不是通过pushState或者replaceState产生的,那么history.state是null。

state对象虽然可以存储很多自定义的属性,但对于不可序列化的对象则不能存储

window.onpopstate事件

window.onpopstate事件主要是监听历史记录点,也就是说监听URL的变化,但会忽略URL的hash部分。

history.go和history.back(包括用户按浏览器历史前进后退按钮)触发,并且页面无刷的时候(由于使用pushState修改了history)会触发popstate事件,事件发生时浏览器会从history中取出URL和对应的state对象替换当前的URL和history.state。通过event.state也可以获取history.state

注意点:

  1. javascript脚本执行window.history.pushState和window.history.replaceState不会触发onpopstate事件。
  2. 谷歌浏览器和火狐浏览器在页面第一次打开的反应是不同的,谷歌浏览器奇怪的是回触发onpopstate事件,而火狐浏览器则不会。

实例Demo

页面css如下:

 body {
overflow-x: hidden;
}
ul {
padding:;
margin:;
list-style-type: none;
}
.header {
font-weight: 18px;
color: red;
height: 100px;
line-height: 100px;
text-align: center;
}
.cho_link {
background: url(../image/choose_bg.png) no-repeat;
} .cho_search {
width: 170px;
margin-right: -20px;
padding-right: 20px;
*vertical-align: -2px;
} .cho_box {
border: 1px solid #bfbfbf;
background-color: #ebebeb;
*position: relative;
overflow-y: hidden;
} .cho_line {
display: block;
padding-top: 2px;
background-color: #d2d2d2;
border-bottom: 1px solid #f0f0f0;
} .cho_left {
width: 20%;
margin-right: 10px;
float: left;
position: relative;
} .cho_menu {
padding-bottom: 72px;
padding-top: 1px;
} .cho_link, .cho_link_on {
display: block;
line-height: 32px;
padding-left: 19px;
color: #333;
*zoom:;
} .cho_link {
background-color: #fafafa;
border-bottom: 1px solid #f6f6f6;
outline: none;
} .cho_link:hover {
background: #f6f6f6;
border-bottom: 1px solid #e0e0e0;
text-decoration: none;
} .cho_link_on {
margin: -1px -1px 0 0;
background: #ebebeb;
border-bottom: 1px solid #ccc;
border-top: 1px solid #ccc;
position: relative;
cursor: default;
} .cho_link_on:first-child {
border-top:;
} .cho_link_on:hover {
text-decoration: none;
}

页面html代码:

<div class="header">head</div>
<div class="center">
<!-- 左边的选菜项 -->
<div class="cho_left">
<ul id="choMenu" class="rel cho_menu">
<li><a href="ajax.aspx?area=pudong" class="cho_link cho_link_on">浦东区</a></li>
<li><a href="ajax.aspx?area=baoshan" class="cho_link">宝山区</a></li>
<li><a href="ajax.aspx?area=jiading" class="cho_link ">嘉定区</a></li>
<li><a href="ajax.aspx?area=qingpu" class="cho_link">青浦区</a></li>
<li><a href="ajax.aspx?area=minhang" class="cho_link">闵行区</a></li>
<li><a href="ajax.aspx?area=putuo" class="cho_link">普陀区</a></li>
<li><a href="ajax.aspx?area=jinshan" class="cho_link">金山区</a></li>
<li><a href="ajax.aspx?area=songjiang" class="cho_link">松江区</a></li>
<li><a href="ajax.aspx?area=zhabei" class="cho_link">闸北区</a></li>
<li><a href="ajax.aspx?area=fengxian" class="cho_link">奉贤区</a></li>
<li><a href="ajax.aspx?area=huangpu" class="cho_link">黄浦区</li>
<li><a href="ajax.aspx?area=changning" class="cho_link">长宁区</a></li>
<li><a href="ajax.aspx?area=jingan" class="cho_link">静安区</a></li>
<li><a href="ajax.aspx?area=zhoubian" class="cho_link">上海周边</a></li>
</ul>
</div> <!-- 右侧主列表 -->
<div class="cell">
<div id="listBox">
右侧显示相应的内容
</div>
</div>
</div>
<div class="header">footer</div>

JS代码:

//给每个左侧链接绑定事件
var eleMenus = $("#choMenu a").bind("click", function (event) {
//获得querystring的值
var query = this.href.split("?")[1];
//将左侧列表链接全部去掉高亮
$("#choMenu a").removeClass('cho_link_on');
//给当前点击的链接加高亮
$(this).addClass('cho_link_on');
//如果存在history.pushState状态 且有queryString的值
if (history.pushState && query) {
var curText = $(this).text();
//给右侧内容框赋值
$('#listBox').text(curText);
// history处理 document.title = "history demo-" + curText;
if (event && /\d/.test(event.button)) {
//history.pushState使得页面的URL地址变化了
history.pushState({ title: title }, title, location.href.split("?")[0] + "?" + query);
}
}
return false;
}); var fnHashTrigger = function (target) {
var query = location.href.split("?")[1], eleTarget = target || null;
//页面首次载入,没有queryString的值
if (typeof query == "undefined") {
if (eleTarget = eleMenus.get(0)) {
// 如果没有查询字符,则使用第一个导航元素的查询字符内容
history.replaceState(null, document.title, location.href.split("#")[0] + "?" + eleTarget.href.split("?")[1]) + location.hash;
fnHashTrigger(eleTarget);
}
} else {
eleMenus.each(function () {
if (eleTarget === null && this.href.split("?")[1] === query) {
eleTarget = this;
}
}); if (!eleTarget) {
// 如果查询序列没有对应的导航菜单,去除查询然后执行回调
history.replaceState(null, document.title, location.href.split("?")[0]);
fnHashTrigger();
} else {
$(eleTarget).trigger("click");
}
}
}; if (history.pushState) {
//页面无刷新的,原先ajax请求的数据加载过来了 这就是popstate事件的作用
window.addEventListener("popstate", function () {
fnHashTrigger();
}); // 默认载入
fnHashTrigger();
}

代码大家可以复制过去自己试一下,代码实现的功能是页面的跳转(前进后退,点击等)不重新请求页面,但是会相应改变右侧区域的内容且url改变了,而且可以通过无刷新的请求回退状态,真的是无限级的提高了用户友好性。

浏览器支持情况

HTML5 history的更多相关文章

  1. HTML5 History API 实现无刷新跳转

     在HTML5中, 1. 新增了通过JS在浏览器历史记录中添加项目的功能. 2. 在不刷新页面的前提下显示改变浏览器地址栏中的URL. 3. 添加了当用户单击浏览器的后退按钮时触发的事件. 通过以上三 ...

  2. HTML5 History API实现无刷新跳转

    在HTML5中, 新增了通过JS在浏览器历史记录中添加项目的功能. 在不刷新页面的前提下显示改变浏览器地址栏中的URL. 添加了当用户单击浏览器的后退按钮时触发的事件. 通过以上三点,可以实现在不刷新 ...

  3. html5 history api

    1.html5 history api适用场景,个人理解最大的用处是配合ajax使用,使ajax拥有回退.前进的用户体验. 2.代码(dive into html5中的一个小例子) 1)fer.htm ...

  4. HTML5 history API实践

    一.history API知识点总结 在HTML4中,我们已经可以使用window.history对象来控制历史记录的跳转,可以使用的方法包括: history.forward();//在历史记录中前 ...

  5. Ajax异步刷新地址栏url改变(利用Html5 history.pushState实现)

    早些时候在博客园参阅了不少资料,然后决定入驻博客园分享自己的开发心得,最近准备转方向筹备着辞职交接工作,所以有点忙碌,搁置了一个月才匆匆写下这么一篇随笔,希望能给大家带来一点帮助吧,资料和学识有限,如 ...

  6. ajax与HTML5 history pushState/replaceState实例

    一.本文就是个实例展示 三点: 我就TM想找个例子,知道如何个使用,使用语法什么的滚粗 跟搜索引擎搞基 自己备忘 精力总是有限的,昨天一冲动,在上海浦东外环之外订了个90米的房子,要借钱筹首付.贷款和 ...

  7. HTML5 History对象,Javascript修改地址栏而不刷新页面(二)

    一.实例说明: $('#btnOne').click(function () { var stateObject = { id: 1 }; var title = "本地首页"; ...

  8. 转: html5 history api详解~很好的文章

    从Ajax翻页的问题说起 请想象你正在看一个视频下面的评论,在翻到十几页的时候,你发现一个写得稍长,但非常有趣的评论.正当你想要停下滚轮细看的时候,手残按到了F5.然后,页面刷新了,评论又回到了第一页 ...

  9. HTML5 History API & URL 重定向

    HTML5 History API & URL 重定向 disabled server url redirect https://developer.mozilla.org/en-US/doc ...

  10. html5 - history 历史管理

    参考文章: w3c     :  http://www.w3.org/html/ig/zh/wiki/HTML5/history 张鑫旭  : http://www.zhangxinxu.com/wo ...

随机推荐

  1. K-means算法和矢量量化

    语音信号的数字处理课程作业——矢量量化.这里采用了K-means算法,即假设量化种类是已知的,当然也可以采用LBG算法等,不过K-means比较简单.矢量是二维的,可以在平面上清楚的表示出来. 1. ...

  2. VI命令----用于检索

    装了个虚拟机Ubuntu,命令行模式用VI很不适应,需要学习! 1.vi 模式切换: Commond模式: 打开文件的默认模式,用ESC建切换到此模式 Insert模式: 按键:i 在光标前输入 a ...

  3. CSS HACK tab制表符导致行内元素之间的空隙如何解决

    <!DOCTYPE html> <html lang="zh-CN"><head> <meta name="viewport&q ...

  4. Rectangles Area Sum

    #include<iostream> #include<stdio.h> #include<math.h> #include<string.h> #in ...

  5. 使用 Spring 3 来创建 RESTful Web Services

    来源于:https://www.ibm.com/developerworks/cn/web/wa-spring3webserv/ 在 Java™ 中,您可以使用以下几种方法来创建 RESTful We ...

  6. oracle-day1

    今天的学习内容是oracle产品的三种安装方式,还有使用dbca静默建库 oracle产品的三种安装方式分别为: 1.图形化(Java向导)安装引导 2.使用应答文件静默安装 3.直接将装好的orac ...

  7. Mysql-报错:1130-host ... is not allowed to connect to this MySql server 开放mysql远程连接 不使用localhost

    报错:1130-host ... is not allowed to connect to this MySql server   解决方法: 1. 改表法. 可能是你的帐号不允许从远程登陆,只能在l ...

  8. Fiddler+Jmeter+断言详细教程

    一.Fiddler抓包工具的配置和使用 在编写网关自动化脚本之前,得先学会如何抓包,这里以Fiddler为例.会抓包的同学可以跳过这一步,当然看看也是没坏处的-- 局域网络配置 将要进行抓包的手机与电 ...

  9. Java 学习之路 之 泛型方法

    前面介绍了在定义类.接口时可以使用类型形参,在该类的方法定义和 Field 定义.接口的方法定义中,这些类型形参可被当成普通类型来用.在另外一些情况下,我们定义类.接口时没有使用类型形参,但定义方法时 ...

  10. java中是否会存在内存泄漏

    会.java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中 ...