浅析jQuery Address Plugin
你是否经历过这样的场景,坐在电脑前,打开网页,看到吸引人的图片,我们兴冲冲的点了进去,一看究竟。
进去后我们大呼上当,“什么破玩意儿啊”,接下来你会怎么做?
关闭网页?又或者是点击“后退”?如果你是“后退综合症”患者,点一下后退,不动,再点一下,又不动,~!@#$%^ 果断关毕这个网页~~
如果我是开发者,我有一个非常多页面的网站,为了不让页面重载,我用Ajax加载这些页面。
但是连我这样的小白都知道,Ajax请求不会改变url,浏览器没法保存历史记录,“前进” “后退”根本不能用~
自己想办法解决,当然没问题,onhashchange啊iframe啊,肯定要花你不少时间,其实有个jQuery有个插件,把这个问题解决了,叫jQuery Address plugin
使用jQuery Address plugin很简单,加一个文件,写几句代码:
<script type="text/javascript" src="jquery.address-1.4.js"></script>
<script type="text/javascript">
$.address.state('这里需要基本URL,地址不改变部分,一般为初始化进入页面地址').init(function(event) {
//插件初始化,一般这里调用 $('.nav a').address(); 实现链接单击监听
}).change(function(event) {
//当页面地址更改的时候调用,即#号之后的地址更改
}).internalChange(function(event) {
//内部地址更改,即非通过手动更改URL#号后的内容
}).bind('externalChange',function(event) {
//外部地址更改,手动修改URL#号后的内容
});
</script>
你肯定想问,他是怎么实现的呢?我看了一下源码,总结了几个关键点:
1.自定义事件
Address定义了四个自定义事件(init,change,internalChange,externalChange),
首次载入时,触发init()事件;
其中只要url变化,会触发change()事件;
点击链接自动改变url时,会触发内部变化internalChange()事件;
点击浏览器前进后退时,会触发外部变化externalChange()事件。
_update:更新器,触发相应的自定义事件
_update = function(internal) {
_trigger(CHANGE);
_trigger(internal ? INTERNAL_CHANGE : EXTERNAL_CHANGE);
_st(_track, 10);
},
_trigger:触发器,触发自定义事件,继承自jquery的trigger()方法。事件触发后,返回一系列location信息:
{
value: $.address.value(),
path: $.address.path(),
pathNames: $.address.pathNames(),
parameterNames: parameterNames,
parameters: parameters,
queryString: $.address.queryString()
}
2.检测hash变化,此处要考虑浏览器兼容性
IE6、7要定时检测hash变化,其他浏览器用window.onhashchange监测。
if (!_supportsState()) {
if ((_msie && _version > 7) || (!_msie && ('on' + HASH_CHANGE) in _t)) {
if (_t.addEventListener) {
_t.addEventListener(HASH_CHANGE, _listen, FALSE);
} else if (_t.attachEvent) {
_t.attachEvent('on' + HASH_CHANGE, _listen);
}
} else {
_si(_listen, 50);
}
}
listen = function() {
if (!_silent) {
var hash = _href(),
diff = _value != hash;
if (diff) {
if (_msie && _version < 7) {
_l.reload();
} else {
if (_msie && _version < 8 && _opts.history) {
_st(_html, 50);
}
_value = hash;
_update(FALSE);
}
}
}
}
支持HTML5的浏览器,引用了新的API,就是history.pushState和history.replaceState,通过这个接口可以做到无刷新改变页面URL。pushState是将指定的URL添加到浏览器历史里,replaceState是将指定的URL替换当前的URL。
if (_supportsState()) {
_h\[_opts.history ? 'pushState' : 'replaceState'\]({}, '',
_opts.state.replace(/\\/$/, '') + (_value === '' ? '/' : _value));
}
响应前进、后退操作,window对象上提供了onpopstate事件。
$(window).bind('popstate', _popstate).bind('unload', _unload);
_popstate = function() {
if (_value != _href()) {
_value = _href();
_update(FALSE);
}
},
IE6、7浏览器要创建iframe/frame,用来保存hash信息:
if (_msie && _version < 8) {
var frameset = _d.getElementsByTagName('frameset')\[0\];
_frame = _d.createElement((frameset ? '' : 'i') + 'frame');
if (frameset) {
frameset.insertAdjacentElement('beforeEnd', _frame);
frameset\[frameset.cols ? 'cols' : 'rows'\] += ',0';
_frame.noResize = TRUE;
_frame.frameBorder = _frame.frameSpacing = 0;
} else {
_frame.style.display = 'none';
_frame.style.width = _frame.style.height = 0;
_frame.tabIndex = -1;
_d.body.insertAdjacentElement('afterBegin', _frame);
}
_st(function() {
$(_frame).bind('load', function() {
var win = _frame.contentWindow;
_value = win\[ID\] !== UNDEFINED ? win\[ID\] : '';
if (_value != _href()) {
_update(FALSE);
_l.hash = _crawl(_value, TRUE);
}
});
if (_frame.contentWindow\[ID\] === UNDEFINED) {
_html();
}
}, 50);
}
_html = function() {
var src = _js() + ':' + FALSE + ';document.open();document.writeln(\\'<html><head><title>' +
_d.title.replace('\\'', '\\\\\\'') + '</title><script>var ' + ID + ' = "' + encodeURIComponent(_href()) +
(_d.domain != _l.hostname ? '";document.domain="' + _d.domain : '') +
'";</' + 'script></head></html>\\');document.close();';
if (_version < 7) {
_frame.src = src;
} else {
_frame.contentWindow.location.replace(src);
}
},
创建的iframe/frame,包含location的hash信息:
<IFRAME style="DISPLAY: none; WIDTH: 0px; HEIGHT: 0px" tabIndex=-1 src="javascript:false;document.open();document.writeln('<html><head><title>jQuery Address Events</title><script>var jQueryAddress = "%2Fjquery%2Faddress%2Fsamples%2Fevents%2Fabout";</script></head></html>');document.close();" jQuery1333892941446="10">
<HTML>
<HEAD>
<TITLE>jQuery Address Events</TITLE>
<SCRIPT>var jQueryAddress = "/jquery/address/samples/events/about";</SCRIPT>
</HEAD>
<BODY></BODY>
</HTML>
</IFRAME>