不使用定时器实现的onhashchange
之前看sparks345 写的《不采用interval方式模仿onHashChange》
后来自己又折腾了一把,完整的源码总共大小是1.66KB(2K不到)
支持:FF3.0+、IE6+、Chrome
主流的浏览器(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);
使用方法,初始化一个实例,然后设置监听器,等待点击浏览器的“前进”、“后退”回调便可。
运行示例代码(初次加载可能无法下载脚本,刷新即可~):
测试用的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>