Router的實現原理
阿新 • • 發佈:2020-08-07
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>