開篇日常立個flag……
前言
最近在做一些應用,類似於單頁應用,想實現類似於 Vue 路由的效果。
但是個人 Vue 基礎四捨五入約等於無,而且看著 Vue-router 吃力+用不起來(因為我的專案前後端不分離,而且使用的 js 語法基本上停留在遠古時代:ES5甚至更久遠以前……)
之前嘗試過模擬,但是模擬太痛苦了,而且一堆問題,還不好維護。
於是想著自己用原生 js 寫一個簡單的單頁應用路由吧。
效果
話不多說,先上效果圖
原始碼
gitee:https://gitee.com/chen3322275/singlepagerouter/
思路與設定
-思路
1、location.hash 可以修改頁面的錨點
2、當前頁面錨點的改變,會觸發 hashchange 事件
這樣,註冊一個 hashchange 事件,監聽 hash 的變化,切換頁面指定元素的顯示與隱藏,可以達到單頁應用的效果。
-一些設定
首先我們約定一個路由物件 route,route 包含兩個屬性,即 id 和 handle。
接著,我們將會設定一個路由表,記錄為 routes,為一個 route 物件的陣列。
最後,實現一個路由器 Router 物件,還監聽以及操作路由跳轉。
三者的定義如下:
//route 單個路由物件 var route = { id: 'next', handle: function () { console.log("切換到next");} //routes 路由表 var routes = [{ id: 'index' }, { id: 'next', handle: function () { console.log("切換到next");} }] //router 路由器 var router = new Router(routes);
註釋:
route 物件的 id,除了為操作元素(一般為 div)的 id 外,還將會是 hash 的值。
handle 為一個函式,類似於回撥函式,在切換該路由時執行。
若 id 為空,則隱藏路由表所有路由。
Router 模組 js程式碼
直接上程式碼
/* * 模組:單頁應用路由 * 作者:cls * 日期:2021.04.17 * 使用:var routes = [{ id: 'index' }, { id: 'next', handle: function () { console.log("切換到next");} }] * var router = new Router(routes); */ function Router(routes, defaultRoute) { var othis = this; //路由初始化 routes && othis.init(routes, defaultRoute); //繫結 hashchange 事件 window.addEventListener("hashchange", function() { let route = location.hash.slice(1) || ""; othis.oldRoute = othis.currentRoute; othis.currentRoute = route; othis.changePage(route); }); } //初始化,可多次初始化 Router.prototype.init = function(routes, defaultRoute) { if (routes == undefined || routes.length == undefined || routes.length == 0) { console.error("Router初始化失敗:routes錯誤!"); return; } this.routes = routes; this.currentRoute = location.hash.slice(1) || defaultRoute || routes[0].id; //當前路由獲取順序 this.oldRoute = ""; location.hash || history.replaceState(null, null, '#' + this.currentRoute); //hash為空,切換當前hash this.changePage(this.currentRoute); this.oldRoute = location.hash; } //切換路由 Router.prototype.push = function(route, callback) { //獲取route switch (typeof(route)) { case "string": break; case "undefined": route = location.hash.slice(1) || ""; break; case "number": route = this.routes[route] || ""; break; case "object": route = route.id || ""; break; } location.hash = route; //切換hash,接下來的事情交給hashchange去做。如果與上一次的route一致,不會觸發hashchange事件 } //切換頁面:route為字串,為空則隱藏所有路由 Router.prototype.changePage = function(route) { for (let i = 0; i < this.routes.length; i++) { let e = document.getElementById(routes[i].id); if (routes[i].id == route) { e && (e.style.display = "block"); (typeof(routes[i].handle) === "function") && routes[i].handle(); //handle 存在,執行函式 } else { e && (e.style.display = "none"); } } }
測試頁面的 Html 程式碼
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>單頁路由測試</title> </head> <body> <div> <h1>Welcome</h1> <a href="#">空的</a> <a href="#index">index啊啊啊</a> <button onclick="router.push('next')">next測試</button> <div id="index"> index啊啊啊 </div> <div id="next"> next啊啊啊 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊 </div> </div> <script src="~/js/site.js"></script> <script> //路由表 var routes = [ { id: '' }, { id: 'index' }, { id: 'next', handle: function () { console.log("切換到next"); console.log(this); } } ] //路由器 var router = new Router(routes, 'index'); </script> </body> </html>
使用說明
1、整個應用生命週期,只建立一次路由器,即 var router = new Router() 時,只 new 一次。(否則會註冊多次 hashchange 事件)
2、路由器建立以後,可以使用 router.init() 切換路由表
3、控制 router 跳轉路由使用 router.push(route) 方法,輸入的 route 可以是路由表的下標,也可以是路由表 id 的字串,也可以是 route 物件,若沒有輸入,則預設不會跳轉。
參考來源
小蚊 的 用原生js做單頁應用(博文掛掉了,連結複製不到)