Router的实现原理
Router
单页面应用(SPA)需配置Router来解决页面跳转,Vue、React等框架都支持Router配置,路由常分为hash、history两种模式。hash模式URL尾部带有“#”,history模式不带“#”。history模式需要配合服务器的URL重写,否则将出现404。下面使用原生JS实现Router。
路由原理
- Router 注册
1.1 提供注册的URL
1.2 提供回调函数 - URL 跳转模式
2.1 push 跳转
2.2 replace 跳转 - Router 监听
3.1 hashRouter 监听
3.2 historyRouter 监听 - Router 模式
4.1 hashRouter
4.2 historyRouter
路由实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Router</title>
</head>
<body>
<!-- push 跳转模式 -->
<ul>
<li onclick="Router.push(baseUrl + '')">首页</li>
<li onclick="Router.push(baseUrl + 'news')">新闻</li>
<li onclick="Router.push(baseUrl + 'products')">产品</li>
</ul>
<!-- replace 跳转模式 -->
<ul>
<li onclick="Router.replace(baseUrl + '')">首页</li>
<li onclick="Router.replace(baseUrl + 'news')">新闻</li>
<li onclick="Router.replace(baseUrl + 'products')">产品</li>
</ul>
<div id="app">
</div>
<script>
var app = document.getElementById("app")
var baseUrl = "/" // 根目录
function RouterClass(options) {
this.routerMap = {} // 用于路由注册
this.curUrl = "" // 当前的url
this.mode = -1
this.modeWhiteList = {
"hash":this.eventHashRouter.bind(this),
"history":this.eventHistoryRouter.bind(this)
}
Object.keys(this.modeWhiteList).forEach((key,index)=>{
if(key === options.mode){
this.mode = index
this.modeWhiteList[key]()
}
})
// 默认为hash模式
if(this.mode === -1){
console.log("default")
this.mode = 0;
this.modeWhiteList['hash']();
}
}
// hash 路由
RouterClass.prototype.hashRouter = function(){
this.curUrl = window.location.hash.slice(1) || "/"
this.routerMap[this.curUrl]()
}
// history 路由
RouterClass.prototype.historyRouter = function(){
this.curUrl = window.location.pathname
console.log(this.curUrl)
this.routerMap[this.curUrl]()
}
/* 事件监听 */
// hash 模式监听
RouterClass.prototype.eventHashRouter = function(){
window.addEventListener("hashchange",this.hashRouter.bind(this))
window.addEventListener("load",this.hashRouter.bind(this))
}
// history 模式监听
RouterClass.prototype.eventHistoryRouter = function(){
window.addEventListener("popstate",this.historyRouter.bind(this))
}
/* 路由注册 */
RouterClass.prototype.register = function(path,callback){
this.routerMap[path] = callback || function(){}
}
/* 跳转模式 */
// push 模式跳转
RouterClass.prototype.push = function(url){
if(this.mode === Object.keys(this.modeWhiteList).indexOf("history")){
window.history.pushState({},"",url)
this.routerMap[url]()
}else{
url = "#" + url;
window.location.href = url;
}
}
// replace 模式跳转
RouterClass.prototype.replace = function (url) {
if(this.mode === Object.keys(this.modeWhiteList).indexOf("history")){
window.history.replaceState({},"",url)
this.routerMap[url]()
}else{
url = "#" + url;
window.location.replace = url;
}
}
var Router = new RouterClass(
{mode:"history"}
);
Router.register(baseUrl + "",function () {
app.innerHTML = "index"
})
Router.register(baseUrl + "news",function () {
app.innerHTML = "news"
})
Router.register(baseUrl + "products",function () {
app.innerHTML = "products"
})
</script>
</body>
</html>