

这两种方式都可以帮我们满足题设条件。采用哪一种方式除了主观喜好之外,还得依照客观事实:低版本的浏览器对于history API的兼容性不好,例如遇到了IE8,摆在眼前的道路似乎就别无选择了。
url变化在浏览器端,跟踪表单属性的变化一般都采用事件监听机制,跟踪url的变化也不落俗套。
对于hash方式的前端路由,通常可以监听 hashchange 事件,在事件回调中处理相应的页面视图展示等逻辑。
此外,HTML5提供的 popstate 事件也会在url的hash发生改变时触发。也就是说如果可以忽略低版本浏览器,我们使用hash方式路由时也可以采用监听这个事件进行回调处理。
那么,如果是采用history API的形式呢?根据MDN的描述:
调用 history.pushState() 或者 history.replaceState() 不会触发 popstate 事件。popstate 事件只会在浏览器某些行为下触发, 比如点击后退按钮(或者在JavaScript中调用 history.back() 方法)。
这也就是说,我们在使用history API改变浏览器的url时,仍需要额外的步骤去触发 popstate 事件,例如调用 history.back() 会 history.forward() 等方法。
从兼容性上来讲,前面有提及hash的方式兼容性更好。然而,对于低版本的浏览器,例如IE6等等,不支持 hashchange 事件。这个时候我们只能通过 setInterval 设置心跳的方式去模拟 hashchange。
var oldHash = location.hash;var oldURL = location.href;setInterval(function() { var newHash = location.hash; var newURL = location.href; if (newHash !== oldHash && typeof window.onhashchange === 'function') { // 执行onhashchange回调
window.onhashchange({ 'type': 'hashchange', 'oldURL': oldURL, 'newURL': newURL
});oldHash = newHash;
oldURL = newURL;
}
}, 100);
这里,给出一个很简单的实现:
router.jsfunction FrontRouter() { this.routes = {};
window.addEventListener('load', this.resolve.bind(this), false);
window.addEventListener('hashchange', this.resolve.bind(this), false);
}FrontRouter.prototype.route = function(path, callback) { this.routes[path] = callback || function() {};
};
FrontRouter.prototype.resolve = function() { this.curHash = location.hash.slice(1) || '/'; typeof this.routes[this.curHash] === 'function' && this.routes[this.curHash]();
};
index.html<ul> <li><a href='#blue'></a></li> <li><a href='#yellow'></a></li> <li><a href='#red'></a></li></ul>
index.jsvar router = new FrontRouter();router.route('blue', function() {
document.body.style.backgroundColor = 'blue';
});router.route('yellow', function() {
document.body.style.backgroundColor = 'yellow';
});router.route('red', function() {
document.body.style.backgroundColor = 'red';
});
前端路由大部分的应用场景,就是我们现在熟知的单页应用SPA。
我们此前所描述的前端路由,建立在已经打开了一个初始页面基础之上,然后在这个页面之内进行页面替换。然而,我们如何进入这个初始页面?仅靠前端路由肯定是力所不及。我们至少要向后端发送一次http请求,接收所需要加载的页面不是吗?
所以,我们并不能抛弃后端路由部分。这也意味着,我们需要和后端确认各自的分工,哪些url归前端解析,哪些归后台解析。
