前端 JS 原生 javascript 和 location.hash 實現一個單頁應用的路由 router

cl_lis發表於2021-04-17

 開篇日常立個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實現單頁應用路由轉跳功能

小蚊 的 用原生js做單頁應用(博文掛掉了,連結複製不到)

相關文章