不使用定时器实现的onhashchange

之前看sparks345 写的《不采用interval方式模仿onHashChange

后来自己又折腾了一把,完整的源码总共大小是1.66KB(2K不到)

 

支持:FF3.0+、IE6+、Chrome

 

image

 

主流的浏览器(IE6、IE7除外),基本上都支持onhashchange事件,而IE8也将支持。只有IE6、IE7不支持,而使用这两个浏览器的用户还是占有很大的一部分份额。

 

网上流传的实现onhashchange方法基本上都采用setInterval来跑,这样做:

第一:不切换也要去检测一次hash,总觉得别扭;

第二:点击过快的时候容易出bug(曾经耿耿于怀这个)

既然外面的轮子都不好用,还就自己造一个吧~

 

其实造也不难,因需要专门针对ie做一些处理就好了。页面放个iframe,然后然后iframe里面的内容,比如加个表单元素input并监听其onload事件,然后回调。

 

说明一下:这个方法不是我最先想到的,是我不经意见研究某站点的代码发现的,在这里先致谢一下。

HistoryManager.js的源码:

 

   1: function HistoryManager() {
   2:     this.listener = null;
   3:     this.adapterIframe = null;
   4:     this._initialize();
   5: }
   6:  
   7: ~(function() {
   8:     var flag = false,
   9:         isIE = !!window.ActiveXObject && /msie (\d)/i.test(navigator.userAgent) ? RegExp['$1'] : false,
  10:         $pointer = this;
  11:     
  12:     this.makeIEHistory = function(url) {
  13:         if (!url) {
  14:             return ;
  15:         }
  16:         
  17:         var frameDoc = $pointer.adapterIframe.contentWindow.document;
  18:         
  19:         frameDoc.open();
  20:         frameDoc.write([
  21:             "<html>",
  22:                 "<head>",
  23:                     "<script type='text/javascript'>",
  24:                         "function pageLoaded() {",
  25:                             "try {top.window.historyManager.fireOnHashChange(\""+url+"\");} catch(ex) {}",
  26:                         "}",
  27:                     "</script>",
  28:                 "</head>",
  29:                 "<body onload='pageLoaded();'>",
  30:                     "<input type='value' value='"+url+"' id='history'/>",
  31:                 "</body>",
  32:             "</html>"
  33:         ].join(""));
  34:         frameDoc.title = document.title;
  35:         frameDoc.close();
  36:     }
  37:  
  38:     this.fireOnHashChange = function(url) {
  39:         location.hash = "#" + url.replace(/^#/, "");
  40:         
  41:         if (window.onhashchange) {
  42:             window.onhashchange();
  43:         }
  44:     }
  45:  
  46:     this.add = function(url) {
  47:         flag = true;
  48:  
  49:         if (isIE && isIE < 8) {
  50:             $pointer.makeIEHistory(url);
  51:         } else {
  52:             location.hash = "#" + url;
  53:         }
  54:     }
  55:  
  56:     this.fire = function(url) {
  57:         if (!url) {
  58:             url = document.location.hash.slice(1);
  59:         }
  60:  
  61:         $pointer.listener(url);
  62:     }
  63:  
  64:     this.addListener = function(fn) {
  65:         $pointer.listener = typeof fn === 'function' ? fn : function() {};
  66:     }
  67:  
  68:     this._initialize = function() {
  69:         if (isIE && isIE < 8) {
  70:             $pointer.adapterIframe = document.getElementById("HISTORY_ADAPTER");
  71:             $pointer.makeIEHistory();
  72:         }
  73:  
  74:         window.onhashchange = function() {
  75:             if (flag) {
  76:                 flag = false;
  77:                 return ;
  78:             }
  79:  
  80:             $pointer.fire();
  81:         }
  82:     }
  83:  
  84: }).call(HistoryManager.prototype);
 

使用方法,初始化一个实例,然后设置监听器,等待点击浏览器的“前进”、“后退”回调便可。

 

image

 

image

 

运行示例代码(初次加载可能无法下载脚本,刷新即可~):

 

 

测试用的HTML源代码:

   1: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
   2: <html>
   3:  <head>
   4:   <title>ajax历史记录</title>
   5:   <meta name="generator" content="editplus" />
   6:   <meta name="author" content="" />
   7:   <meta name="keywords" content="" />
   8:   <meta name="description" content="" />
   9:   <meta http-equiv="content-type" content="text/html;charset=utf-8">
  10:   <style type="text/css">
  11:     a {display:inline-block; margin-right:10px;}
  12:     #clickHistory {border:1px solid #406c99; padding:15px; margin-top:10px; width:600px;}
  13:   </style>
  14:  </head>
  15:  
  16:  <body>
  17:  
  18:     <!--[if IE]><iframe id="HISTORY_ADAPTER" src="ajaxhistory.html" style="display:none"></iframe><![endif]-->
  19:   <a href="#/1111/kk.html">Test1</a><a href="#/2222/kk.html">Test2</a><a href="#/3333/kk.html">Test3</a>
  20:  
  21: <div id="clickHistory">I am the #1 ajax container..</div>
  22:  
  23:   <script type="text/javascript" src="https://files.cnblogs.com/meteoric_cry/historyFrame.js"></script>
   1:  
   2:   <script type="text/javascript">
   3:     var historyManager = new HistoryManager();
   4:  
   5:     historyManager.addListener(function() {
   6:         var url = arguments[0];
   7:  
   8:         alert("当前的改变后的URL:" + url);
   9:         
  10:         setHashHistory(url);
  11:     });
  12:  
  13:     document.onclick = function(ev) {
  14:         ev = ev || window.event;
  15:         var elem = ev.srcElement || ev.target;
  16:  
  17:         if (elem.tagName && elem.tagName.toLowerCase() == "a") {
  18:             if (ev.preventDefault) {
  19:                 ev.preventDefault();    
  20:             } else {
  21:                 ev.returnValue = false;
  22:             }
  23:             
  24:             var href = elem.getAttribute("href", 2);
  25:             historyManager.add(href);
  26:  
  27:             setHashHistory(href);
  28:         }
  29:     }
  30:  
  31:     function setHashHistory(_url) {
  32:         var tid = _url.replace(/[^\/]?\/(\d+)\/(.*)/, "$1");
  33:         var colorConfig = {
  34:             '1111' : '#2B6088',
  35:             '2222' : '#FD1B15',
  36:             '3333' : '#FF6D06'
  37:         }
  38:         
  39:         var elem = document.getElementById("clickHistory");
  40:         var html = elem.innerText || elem.contextText;
  41:  
  42:         elem.innerHTML = html.replace(/\#(\d+)\s/, "#" + tid + " ");
  43:         elem.style.backgroundColor = colorConfig[tid];
  44:     }    
  45:   
</script>
  24:  </body>
  25: </html>
posted @ 2011-01-11 19:01  meteoric_cry  阅读(5988)  评论(6编辑  收藏  举报