首页 > Javascript > 告别定时器,兼容IE实现onhashchange

告别定时器,兼容IE实现onhashchange

不使用定时器,让ajax实现历史记录功能。

兼容性:FF3.0+、IE6+、Chrome

源码大小:1.76KB(未压缩),下载地址见文末。

常用ajax的同学应该对onhashchange并不陌生,ajax并不是一个完美的东西,无刷新的页面会导致我们丢失本该有的浏览器历史记录,通常我们需要通过url hash来手动的产生浏览器历史记录,从而使“后退”/“前进”按钮有效。所以,还没有关注这点的同学也需要注意onhashchange了,有“后退”/“前进”功能的页面才是一个好页面。

遗憾的是onhashchange事件是html5里新增加的,所以一些古老的浏览器并不支持它,目前的支持情况如下(via):

IE 的部份,IE8 之后才有支持:「onhashchange Event」

Firefox 则是 3.6 之后才有支持:「window.onhashchange」

Webkit 是 528 版以后 (2009/08/07 的 ticket):「Support for HTML5 "hashchange" event」,对应的版本是 Google Chrome 1.0.154 之后,以及 Safari 4.0+

对于不支持的浏览器,可以使用隐藏的iframe来达到更改浏览器历史记录的目的。


HistoryManager.js源码如下:

function HistoryManager() {
	this.listener = null;
    this.adapterIframe = null;
    this._initialize();
}

~(function() {
	var flag = false,
	isIE = !!window.ActiveXObject && /msie (\d)/i.test(navigator.userAgent) ? RegExp['$1'] : false,
	pointer = this;
	
	this.makeIEHistory = function(url) {
		if (!url) {
			return ;
		}
		
		var frameDoc = pointer.adapterIframe.contentWindow.document;
		
		frameDoc.open();
		frameDoc.write([
			"<html>",
				"<head>",
					"<script type='text/javascript'>",
						"function pageLoaded() {",
							"try {top.window.historyManager.fireOnHashChange(\""+url+"\");} catch(ex) {}",
						"}",
					"</script>",
				"</head>",
				"<body onload='pageLoaded();'>",
					"<input type='value' value='"+url+"' id='history'/>",
				"</body>",
			"</html>"
		].join(""));
		frameDoc.title = document.title;
		frameDoc.close();
	}

	this.fireOnHashChange = function(url) {
		location.hash = "#" + url.replace(/^#/, "");
		
		if (window.onhashchange) {
			window.onhashchange();
		}
	}

	this.add = function(url) {
		flag = true;

		if (isIE && isIE < 8) {
			pointer.makeIEHistory(url);
		} else {
			location.hash = "#" + url.replace(/^#/, "");
		}
	}

	this.fire = function(url) {
		if (!url) {
			url = document.location.hash.slice(1);
		}
		pointer.listener(url);
	}

	this.addListener = function(fn) {
		pointer.listener = typeof fn === 'function' ? fn : function() {};
	}

	this._initialize = function() {
		if (isIE && isIE < 8) {
			pointer.adapterIframe = document.getElementById("HISTORY_ADAPTER");
			pointer.makeIEHistory();
		}

		window.onhashchange = function() {
			if (flag) {
				flag = false;
				return ;
			}

			pointer.fire();
		}
	}

}).call(HistoryManager.prototype);


测试html源码如下:

<!DOCTYPE HTML>
<html>
  <head>
    <title>ajax历史记录</title>
    <meta name="keywords" content="" />
    <meta name="description" content="" />
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <style type="text/css">
      a {display:inline-block; margin-right:10px;} #clickHistory {border:1px
      solid #406c99; padding:15px; margin-top:10px; width:600px;}
    </style>
  </head>
  
  <body>
    <!--[if IE]>
      <iframe id="HISTORY_ADAPTER" src="ajaxhistory.html" style="display:none"></iframe>
    <![endif]-->
    <a href="#111.html">
      Test1
    </a>
    <a href="#222.html">
      Test2
    </a>
    <a href="#333.html">
      Test3
    </a>
    <div id="clickHistory">
      默认页面
    </div>
    <script type="text/javascript" src="jquery-1.11.1.min.js"></script>
    <script type="text/javascript" src="HistoryManager.js">
    </script>
		
    <script type="text/javascript">
		var historyManager = new HistoryManager();
		historyManager.addListener(function () {
			var url = arguments[0];
			alert("当前的改变后的URL:" + url);
			setHashHistory(url);
		});
		document.onclick = function (ev) {
			ev = ev || window.event;
			var elem = ev.srcElement || ev.target;
			if (elem.tagName && elem.tagName.toLowerCase() == "a") {
				if (ev.preventDefault) {
					ev.preventDefault();
				} else {
					ev.returnValue = false;
				}
				var href = elem.getAttribute("href", 2);
				historyManager.add(href);
				setHashHistory(href);
			}
		}
		function setHashHistory(_url) {
			//这里可以当前要显示的网址,通过ajax请求网址得到页面并显示
			$.ajax({
				url : _url.replace(/^#/, ''),
				success: function(data){
					$("#clickHistory").html(data);
				},
				error: function(XMLHttpRequest, textStatus, errorThrown){
					$("#clickHistory").html(errorThrown);
				}
			})
			
		}
		$(document).ready(function(){
			if(location.hash){
				setHashHistory(location.hash);
			}
		})
    </script>
  </body>

</html>


3个html嵌入页面源码如下:

<font color="#2B6088">I am the #111 ajax container..</font>
<font color="#FD1B15">I am the #222 ajax container..</font>
<font color="#FF6D06">I am the #333 ajax container..</font>

chrome和firefox下的不贴图了,只贴IE6下的:

初始页面:

default.png

按顺序点击Test1,Test2,Test3之后:

很明显,333.html被load到div中了,然后点击IE6的后退按钮:

这时再点击确定,会发现历史记录中的222.html被load回来。

就是这么简单,感谢meteoric_cry的代码。


源码和测试文件下载地址:

不使用定时器实现的onhashchange.zip


注意:本测试案例必须在网站目录下测试,引入了jquery的ajax加载页面功能,在桌面测试无效哦。


本文地址:http://blog.zhengshuiguang.com/js/onhashchange.html

转载随意,但请附上文章地址:-)

标签:onhashchange iframe 历史记录 兼容ie 完善ajax 前进 后退

相关文章

评论已关闭