目前來說,無論是vue,還是react,spa的路由實(shí)現(xiàn)方式無非就是以下兩者
1.hash方式。 使用location.hash和hashchange事件實(shí)現(xiàn)路由
2.history api。使用html5的history api實(shí)現(xiàn),主要就是popState事件等。
hash用的還是比較多的,但是這種方式的url會比較丑陋,會出現(xiàn) #; 而history api就可以很好的解決這個問題,但是需要后端配置,并且由于是html5中的api,所以兼容性還不是很好
路由實(shí)現(xiàn)之hash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>router</title>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
div.router-wrap {
width: 100%;
height: 100%;
background: #fefefe;
}
a {
padding: 10px;
color: pink;
font-size: 25px;
font-weight: bold;
text-decoration: none;
}
</style>
</head>
<body>
<div class="router-wrap">
<a href="#/black">黑色</a><br>
<a href="#/green">綠色</a><br>
<a href="#/red">紅色</a>
</div>
<script>
// 創(chuàng)建Router構(gòu)造函數(shù)
// currentHash為當(dāng)前hash值,routes為路徑對象
function Router() {
this.currentHash = '/';
this.routes = {};
}
// 注冊路徑,每個路徑對應(yīng)一個回調(diào)函數(shù)。
Router.prototype.route = function(path, callback) {
this.routes[path] = callback || function() {
alert('未定義回調(diào)函數(shù)!');
}
}
// 更新頁面函數(shù)
Router.prototype.refresh = function() {
this.currentHash = location.hash.slice(1) || '/';
this.routes[this.currentHash]();
}
// 初始化
Router.prototype.init = function() {
var self = this;
window.addEventListener('load', function() {
self.refresh();
}, false);
window.addEventListener('hashchange', function() {
self.refresh();
});
}
</script>
<script>
var wrap = document.querySelector('.router-wrap');
window.Router = new Router();
Router.route('/', function() {
wrap.style.backgroundColor = '#fefefe';
});
Router.route('/black', function() {
wrap.style.backgroundColor = 'black';
});
Router.route('/green', function() {
wrap.style.backgroundColor = 'green';
});
Router.route('/red', function() {
wrap.style.backgroundColor = 'red';
});
Router.init();
</script>
</body>
</html>
路由實(shí)現(xiàn)之history API
html5中的history api包括兩個方法history.pushState()和history.replaceState(),包含一個事件history.onpopstate。參考MDN

1044137-20170824080502933-232401939.png
注意:因?yàn)閜ushState的url和當(dāng)前的Url必須是同源的,而file://的形式是不存在同源的說法的,所以我們必須用http://localhost的方式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>router</title>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
}
div.router-wrap {
width: 100%;
height: 100%;
background: #efefef;
}
a {
display: inline-block;
padding: 10px;
color: pink;
font-size: 25px;
font-weight: bold;
text-decoration: none;
}
</style>
</head>
<body>
<div class="router-wrap">
<a href="/black" class="history-link">黑色</a><br>
<a href="/green" class="history-link">綠色</a><br>
<a href="/red" class="history-link">紅色</a>
</div>
<script>
// 創(chuàng)建Router構(gòu)造函數(shù)
function Router() {
this.currentRoute = '';
this.routes = {};
this.init();
}
// 注冊路由函數(shù)
Router.prototype.route = function(path, callback) {
// 根據(jù)type類型,選擇相應(yīng)的history api。
this.routes[path] = function(type) {
if(type == 1) {
history.pushState({
path: path
}, '', path);
} else if(type == 2) {
history.replaceState({
path: path
}, '', path);
}
callback();
}
}
// 更新頁面
Router.prototype.refresh = function(path, type) {
this.routes[path](type);
}
// 初始化
Router.prototype.init = function() {
var self = this;
// 重新加載函數(shù),這里使用的主機(jī)是http://localhost:8088/
window.addEventListener('load', function() {
self.currentRoute = location.href.slice(location.href.indexOf('/', 8));
console.log(self.currentRoute);
self.refresh(self.currentRoute);
});
// 當(dāng)用戶點(diǎn)擊前進(jìn)后退按鈕時(shí)觸發(fā)函數(shù)
window.addEventListener('popstate', function() {
console.log('history.state.path:', history.state.path);
self.currentRoute = history.state.path;
self.refresh(self.currentRoute, 2);
}, false);
// 對所有的link標(biāo)簽進(jìn)行綁定事件
var historyLinks = document.querySelectorAll('.history-link');
for(var i = 0, len = historyLinks.length; i < len; i++) {
historyLinks[i].onclick = function(e) {
// 阻止默認(rèn)
e.preventDefault();
self.currentRoute = e.target.getAttribute('href');
self.refresh(self.currentRoute, 1);
}
}
}
</script>
<script>
var wrap = document.querySelector('.router-wrap');
// 實(shí)例化Router
window.Router = new Router();
// 注冊路由,實(shí)現(xiàn)相應(yīng)功能
Router.route('/', function() {
wrap.style.backgroundColor = '#efefef'
});
Router.route('/black', function() {
wrap.style.backgroundColor = 'black';
});
Router.route('/green', function() {
wrap.style.backgroundColor = 'green';
});
Router.route('/red', function() {
wrap.style.backgroundColor = 'red';
});
</script>
</body>
</html>