早期传统的服务端路由,直接根据 url 来 reload 页面,页面变得越来越复杂服务器端压力变大。随着 ajax 的出现,页面实现非 reload 就能刷新数据,也给前端路由的出现奠定了基础。单页面应用的实现,就是因为前端路由。
单页应用(SPA)应运而生。在url地址改变的过程中,通过js来实现不同UI之间的切换(js对DOM的操作),而不再向服务器重新请求页面,只通过ajax向服务端请求数据,对用户来说这种无刷新的、即时响应是更好的体验。
1.PushState (history.pushState()+popState事件)
原理:HTML5中history对象上新的API,同样能实现前端的路由。通过pushState()方法或replaceState()方法可以修改url的地址,并在popstate事件中能监听地址的改变,不同的是,手动的进行pushState()并不会触发popstate事件。
API: history.pushState 和 history.replaceState
两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。
用history实现一个前端路由
主要代码:
<body>
<div class="menu">
<a href="/home/">首页</a>
<a href="/profile">个人中心</a>
<a href="/articles">文章列表</a>
</div>
<div class="content">
</div>
</body>
<script>
window.onload=function(){
const $ = (selector) => document.querySelector(selector);
class Router {
constructor (routeMap) {
this.routeMap = routeMap;
this._bindPopState();
}
init (path) {
path = Router.correctPath(path);
history.replaceState({path: path}, '', path);
this.routeMap[path] && this.routeMap[path]();
}
go (path) {
path = Router.correctPath(path);
history.pushState({path: path}, '', path);
this.routeMap[path] && this.routeMap[path]();
}
_bindPopState () {
window.addEventListener('popstate', (e) => {
const path = e.state && e.state.path;
this.routeMap[path] && this.routeMap[path]();
});
}
static correctPath (path) {
if (path !== '/' && path.slice(-1) === '/') {
// console.log(path.match(/(.+)\/$/i))
path = path.match(/(.+)\/$/)[1];
}
return path;
}
}
const routeMap = {
'/home': () => {
const content = $('.content');
content.innerHTML = '<div>welcome to Home Page</div>';
},
'/profile': () => {
const content = $('.content');
content.innerHTML = '<div>welcome to Profile Page</div>';
},
'/articles': () => {
const content = $('.content');
content.innerHTML =
'<div>' +
'<p>welcome to Article Page</p>' +
'<ul>' +
'<li>文章1</li>' +
'<li>文章2</li>' +
'<li>文章3</li>' +
'</ul>' +
'</div>';
}
};
const router = new Router(routeMap);
router.init(location.pathname);
$('.menu').addEventListener('click', (e) => {
if (e.target.tagName === 'A') {
e.preventDefault();
router.go(e.target.getAttribute('href'))
}
});
}
</script>

2.Hash(location.hash+hashchange事件)
原理:url 中常会出现 #,一可以表示锚点(如回到顶部按钮的原理),二是路由里的锚点(hash)。Web 服务并不会解析 hash,也就是说 # 后的内容 Web 服务都会自动忽略,但是 JavaScript 是可以通过 window.location.hash
读取到的,读取到路径加以解析之后就可以响应不同路径的逻辑处理。
hashchange 事件
(监听 hash 变化触发的事件),当用 window.location 处理哈希的改变时不会重新渲染页面,而是当作新页面加到历史记录中,这样我们跳转页面就可以在 hashchange 事件中注册 ajax 从而改变页面内容。
<body>
<div class="menu">
<a href="#/home/">首页</a>
<a href="#/profile">个人中心</a>
<a href="#/articles">文章列表</a>
</div>
<div class="content">
</div>
</body>
<script>
window.onload=function(){
const $ = (selector) => document.querySelector(selector);
function Router(routeMap){
this.routeMap = routeMap;
}
Router.prototype={
constructor:Router,
init:function(path) {
window.addEventListener('hashchange',this.go.bind(this),false);
path = this.correctPath(path);
this.routeMap[path] && this.routeMap[path]();
},
go:function () {
var path = location.hash;
path=this.correctPath(path);
this.routeMap[path] && this.routeMap[path]();
},
correctPath:function(path) {
path=path.slice(1);
if (path !== '/' && path.slice(-1) === '/') {
// console.log(path.match(/(.+)\/$/i))
path = path.match(/(.+)\/$/)[1];
}
// console.log(path)
return path;
}
}
const routeMap = {
'/home': () => {
const content = $('.content');
content.innerHTML = '<div>welcome to Home Page</div>';
},
'/profile': () => {
const content = $('.content');
content.innerHTML = '<div>welcome to Profile Page</div>';
},
'/articles': () => {
const content = $('.content');
content.innerHTML =
'<div>' +
'<p>welcome to Article Page</p>' +
'<ul>' +
'<li>文章1</li>' +
'<li>文章2</li>' +
'<li>文章3</li>' +
'</ul>' +
'</div>';
}
};
const router = new Router(routeMap);
router.init(location.hash);
}
</script>
3.前端路由优缺点
优点
用户体验好,不需要每次都从服务器全部获取,快速展现给用户
缺点
不利于SEO
使用浏览器的前进,后退键的时候重新发送请求,没有合理利用缓存
好文推荐
浅谈前端路由
网友评论