onhashchange事件是针对AJAX无缝刷新导致后退键失效而产生的事件,因此属于一个够新的事件,浏览器兼容性如下:
Feature |
Chrome |
Firefox |
IE |
Opera |
Safari |
support |
5.0 |
3.6 (1.9.2) |
8.0 |
10.6 |
5.0 |
由于chrome引发的版本号竞赛,现在chrome20+,firefox16+,opera12了,因此对于标准浏览器我们不必顾虑支持问题,精力集中在IE678上。IE8在兼容模式下虽然有此事件,但不生效。这个检测也很简单。至于如何产生历史,这也很简单,直接在隐藏iframe中调用document.write方法就行。hash的变化,是通过定时器检测,不十分及时,但对于坚持IE67的操蛋用户就不应该给好脸色他们看!
如何观察hash的变化呢?这其实有三个hash值,一个是主窗口之前的hash值(last_hash),主窗口当前的hash值,一个是iframe中的hash值(history_hash),我们可以比较前两者得知hashchange,但当用户点击后退按钮后,AJAX引发的效果是作用于iframe中的,因此这时是比较last_hash与history_hash。发生变化后,我们再手动修改主窗口的hash,触发onhashchange回调。
最后提一提hash值的提取,这里存在两个兼容性问题:
IE6直接用location.hash取hash,可能会取少一部分内容:
比如 http://www.cnblogs.com/rubylouvre#stream/xxxxx?lang=zh_c
ie6 => location.hash = #stream/xxxxx
其他浏览器 => location.hash = #stream/xxxxx?lang=zh_c
firefox 会自作多情对hash进行decodeURIComponent
比如 http://www.cnblogs.com/rubylouvre/#!/home/q={%22thedate%22:%2220121010~20121010%22}
firefox 15 => #!/home/q={"thedate":"20121010~20121010"}
其他浏览器 => #!/home/q={%22thedate%22:%2220121010~20121010%22}
下面是mass Framework中的实现
define( "hashchange" , [ "$event" ], function (){ |
$.log( "已加载hashchange模块 by 司徒正美" ) |
var hashchange = 'hashchange' , DOC = document, documentMode = DOC.documentMode, |
supportHashChange = ( 'on' + hashchange in window) && ( documentMode === void 0 || documentMode > 7 ); |
$.fn[ hashchange ] = function (callback){ |
return callback? this .bind(hashchange, callback ) : this .fire( hashchange); |
$.fn[ hashchange ].delay = 50; |
$.log( "不支持hashchange,使用iframe加定时器模拟" ) |
var iframe, timeoutID, html = '<!doctype html><html><body>#{0}</body></html>' |
if ( $.fn[ hashchange ].domain){ |
html = html.replace( "<body>" , "<script>document.domain =" + |
$.fn[ hashchange ].domain + "</script><body>" ) |
function getHash ( url) { //用于取得当前窗口或iframe窗口的hash值 |
return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' ); |
return getHash(iframe.location); |
function setHistory(hash, history_hash){ |
var doc = iframe.document; |
if ( hash !== history_hash ) { //只有当新hash不等于iframe中的hash才重写 |
doc.write($.format(html, hash)); |
var last_hash = getHash(), history_hash, hash = "#" ; |
$.eventAdapter[ hashchange ] = { |
$.require( "ready" , function (){ |
//iframe是直接加载父页面,为了防止死循环,在DOM树未建完之前就擦入新的内容 |
var el = $( '<iframe tabindex="-1" style="display:none" widht=0 height=0 title="empty" />' ).appendTo( document.body )[0], fn |
iframe = el.contentWindow |
$.bind(el, "load" ,fn = function (){ |
var doc = iframe.document |
doc.write($.format(html, hash)) |
timeoutID = setInterval(poll, $.fn[ hashchange ].delay) |
var hash = getHash(), //取得主窗口中的hash |
history_hash = iframe.document.body.innerText; //取得现在iframe中的hash |
if (hash !== last_hash){ //如果是主窗口的hash发生变化 |
setHistory(last_hash = hash, history_hash ) |
$(desc.currentTarget).fire(hashchange) |
} else if (history_hash !== last_hash){ //如果按下回退键, |
location.href = location.href.replace( / #.*/, '' ) + history_hash; |
具体例子可见这里
打开后点击“运行代码”,然后点击页面触发hashchange,它的回调会在页面添加一行红字,然后再点击后退按钮就看到效果了。
- [ javascript ] 司徒正美的fadeOut-fadeIn效果!
首先感谢司徒正美的文章! 在司徒大神的博客看到一个简单的渐入渐出的效果.全然採用js实现. 例如以下: <!doctype html> <html dir="ltr&quo ...
- [web前端] 去哪儿网前端架构师司徒正美:如何挑选适合的前端框架?
原文地址: https://www.jianshu.com/p/6327d4280e3b 最近几年,前端技术迅猛发展,差不多每年都会冒出一款主流的框架. 每次新开业务线或启动新项目时,首先第一件事就是 ...
- javascript 45种缓动效果BY司徒正美
javascript 45种缓动效果 参数 类型 说明 el element 必需,为页面元素 begin number 必需,开始的位置 change number 必需,要移动的距离 durati ...
- html标签对应的英文原文 - 司徒正美
标签 对应英文 说明 <!--> / 注释 <!DOCTYPE> document type 文档类型 <a> anchor 超链接 <abbr> ab ...
- onhashchange事件,只需要修改hash值即可响应onhashchange事件中的函数(适用于上一题下一题和跳转页面等功能)
使用实例: 使用onhashchange事件做一个简单的上一页下一页功能,并且当刷新页面时停留在当前页 html: <!DOCTYPE html><html><body& ...
- 深入理解JavaScript的闭包特性如何给循环中的对象添加事件
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- JS 事件代理
事件处理器:onclick.onmouseover.... 在传统的事件处理中,你需要为每一个元素添加或者是删除事件处理器.然而,事件处理器将有可能导致内存泄露或者是性能下降——你用得越多这种风险就越 ...
- javascript事件代理(Event Delegation)
看了几篇文章,放上来供参考 司徒正美的文章,Event Delegation Made Easy --------------------------------------------------- ...
- 了解javascript中的事件(二)
本文目录如下: 零.寒暄 一.事件的分类 二.事件代理 2.1 问题引出 2.2 什么是事件代理 2.3 完整示例 二.事件代理 三.事件代理思想的用处 四.总结 零.寒暄 这篇博客本该出现在两个月以 ...
随机推荐
- Ubuntu下QT控制台程序无法运行的解决方案以及XTerm的配置方法
Ubuntu下QT控制台程序无法运行的解决方案以及XTerm的配置方法 最近由于老师要求要在Ubuntu下QT上进程多线程服务器的开发,虽然只是单纯的调用qt的network模块,但是为了避免麻烦,我 ...
- 理解Java多态
多态又称Polymophism,poly意思为多,polymophism即多种形态的意思.一种类型引用因为指向不同的子类,表现出不同的形态,使用不同的方法. 什么是多态 多态建议我们编码时使用comm ...
- poj 1401---求N!末尾0的个数,2的个数一定比5多,观察得来,0的产生即为2*5,去找这个阶乘一行里面5的个数即可
#include<stdio.h> #include<stdlib.h> int main() { int T,N; while(scanf("%d",&a ...
- linux(debian) 安装jdk
#vi /etc/profile 在里面添加如下内容 export JAVA_HOME=/usr/java/jdk1.6.0_27 export JAVA_BIN=/usr/java/jdk1.6.0 ...
- Android UI SurfaceView的使用-绘制组合图型,并使其移动
绘制容器类: //图形绘制容器 public class Contanier { private List<Contanier> list; private float x=0,y=0; ...
- Train Problem II(卡特兰数+大数乘除)
Train Problem II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- Network()
Network Time Limit : 2000/1000ms (Java/Other) Memory Limit : 60000/30000K (Java/Other) Total Submi ...
- Java入门基础总结(二)
判断语句 if else 如下: 1 /* 2 语法: 3 if(条件) 4 { 5 ...
- VB.NET的反射机制
1.前提 Net的应用程序由几个部分:‘程序集’.‘模块’.‘类型’组成. 装配件是.Net应用程序执行的最小单位,编译出来的.dll..exe都是装配件. 2.概念 反射是获得运行时类型的方式. 概 ...
- 如何更快速加载你的JS页面
确保代码尽量简洁 不要什么都依赖JavaScript.不要编写重复性的脚本.要把JavaScript当作糖果工具,只是起到美化作用.别给你的网站添加大量的JavaScript代码.只有必要的时候用一下 ...