前端 JS 原生 javascript 和 location.hash 实现一个单页应用的路由 router

 开篇日常立个flag……

 

前言

最近在做一些应用,类似于单页应用,想实现类似于 Vue 路由的效果。

但是个人 Vue 基础四舍五入约等于无,而且看着 Vue-router 吃力+用不起来(因为我的项目前后端不分离,而且使用的 js 语法基本上停留在远古时代:ES5甚至更久远以前……)

之前尝试过模拟,但是模拟太痛苦了,而且一堆问题,还不好维护。

于是想着自己用原生 js 写一个简单的单页应用路由吧。

 

效果

话不多说,先上效果图

前端 JS 原生 javascript 和 location.hash 实现一个单页应用的路由 router

 

源码

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做单页应用(博文挂掉了,链接复制不到)

上一篇:禁忌搜索算法求解带时间窗的车辆路径规划问题详解(附Java代码)


下一篇:node routes.js