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) { |
return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' ); |
return getHash(iframe.location); |
function setHistory(hash, history_hash){ |
var doc = iframe.document; |
if ( hash !== history_hash ) { |
doc.write($.format(html, hash)); |
var last_hash = getHash(), history_hash, hash = "#" ; |
$.eventAdapter[ hashchange ] = { |
$.require( "ready" , function (){ |
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) |
history_hash = iframe.document.body.innerText; |
setHistory(last_hash = hash, history_hash ) |
$(desc.currentTarget).fire(hashchange) |
} else if (history_hash !== last_hash){ |
location.href = location.href.replace( / #.*/, '' ) + history_hash; |
具体例子可见这里
打开后点击“运行代码”,然后点击页面触发hashchange,它的回调会在页面添加一行红字,然后再点击后退按钮就看到效果了。