2

路由发展

以前的路由都是由后端实现的,根据url来重新载入页面。但是近年来前端页面变得越来越复杂导致服务器端压力越来越大。自然出现了解决方案,通过url的改变,在不刷新页面的情况下,修改页面内容,这就是本文将要介绍的前端路由。


路由分类

前端路由的两种实现方式:

  • 利用history对象实现前端路由
  • 监听window对象的hashchange事件实现前端路由,就是本文重点介绍的hash路由

hash路由

何为hash

  • hash即URL中"#"字符后面的部分。
  • hash值的改变不会导致页面重新加载。
  • 通过window.location.hash属性获取和设置hash值。

直接进入栗子,通过代码来讲解hash路由原理。
我们要实现的效果就是点击左侧导航按钮,切换至对应的路由,并且改变内容区域显示。
也可以手动改变路由地址,然后内容区域也随之变化。
如图所示:
在这里插入图片描述
在这里插入图片描述
100行左右的代码就可以实现这样简单的效果。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>route demo</title>
    <style>
        * {padding: 0;margin: 0;}
        ul li {list-style: none;text-align: center;}
        .main {display: flex;height: 600px;}
        .main .sidebar {width: 200px;border: 2px solid red;}
        .main .sidebar ul {padding-top: 100px;}
        .main .sidebar ul li {margin-bottom: 20px;cursor: pointer; }
        .main .content {flex: 1;border: 2px solid green;padding: 20px;}
    </style>
</head>

<body>
    <div class="main">
        <div class="sidebar">
            <ul class="sidebar-ul">
                <li class="stuManage">学生管理</li>
                <li class="lesManage">课程管理</li>
                <li class="claManage">班级管理</li>
            </ul>
        </div>
        <div class="content"></div>
    </div>
    <script>
        // 定义Route,路由对象构造函数
        function Route(option) {
            this.routes = option.routes;
            this.init();
        }

        // 为Route添加原型方法
        Route.prototype = {
            constructor: Route,
            // 初始化
            init() {
                // 监听window对象的hashchange事件来获取路由的变化
                window.addEventListener("hashchange", (function (e) {
                    // e.oldURL  e.newURL
                    // 获取改变后的hash值
                    var hash = location.hash.substring(1);

                    // 将hash跟本地保存的的路由中的path进行匹配,匹配到指定路由,就执行指定模块的代码
                    // 如果找不到符合条件的元素,那么route值为空
                    var route = this.routes.find(item => {
                        return item.path === hash;
                    }); 
                    if (route) {
                        route.component(hash);
                    }
                }).bind(this));

                // 注册好事件后,立即触发事件,在浏览器刷新后不会触发window的hashchange事件,所以需要手动触发
                var changeEvent = new Event('hashchange');
                window.dispatchEvent(changeEvent);
            },
            // 路由跳转
            push({path}) {
                if (path) {
                    location.hash = "#" + path;
                }
            }
        }

        // 根据路由的改变切换页面显示内容
        function changePage(page) {
            var contentDom = document.querySelector('.main .content');
            if (page === '/' || page === '/student') {
                contentDom.innerHTML = 'student module';
            } else if (page === '/lesson') {
                contentDom.innerHTML = 'lesson module';
            } else if (page === '/class') {
                contentDom.innerHTML = 'class module';
            }
        }

        window.onload = function () {
            // 调用构造函数,实例化路由对象,初始化路由配置
            var router = new Route({
                routes: [
                    { path: "/", component: changePage },
                    { path: "/student", component: changePage },
                    { path: "/lesson", component: changePage },
                    { path: "/class", component: changePage }
                ]
            });

            // 为导航注册点击事件切换路由
            document.querySelector('.sidebar-ul').addEventListener("click", function (e) {
                if (e.target.nodeName == "LI") {
                    var domClassName = e.target.className;
                    if (domClassName.indexOf('stuManage') > -1) {
                        router.push({ path: "/student" })
                    } else if (domClassName.indexOf('lesManage') > -1) {
                        router.push({ path: "/lesson" })
                    } else if (domClassName.indexOf('claManage') > -1) {
                        router.push({ path: "/class" })
                    }
                }
            })
        }

    </script>
</body>

</html>

新建一个html文件,将代码复制过去即可运行。可以尝试点击按钮切换路由,或者手动输入路由进行切换。
下面逐步解读代码,

1.首先来看,最核心的就是Route构造函数以及为Route添加原型方法。
Route构造函数中做了两步操作,1.接收参数。2.调用原型上的init初始化方法。
再来看原型上的两个方法,

  • init方法:实现hash路由的核心。方法内第一步就为window对象的hashchange事件添加监听,那什么时候会触发hashchange事件呢。我在上面已经解释了什么是hash值,那么当hash值发生改变的时候,就会触发hashchange事件,事件对象可以拿到oldURLnewURL两个属性,分别代表改变前的url和改变后的url。当然也可以通过window.location.hash直接拿到hash值(包含#)。拿到hash值后要做的就是遍历传入的路由配置参数,如果有匹配的hash值就执行对应的操作。
  • push方法:提供给外界调用,跳转路由的方法。通过传递的参数改变url中hash值。

2.调用Route构造函数实例化一个route对象var router = new Route(),参数就是我们的路由配置。配置中path就是改变的hash值,component就是匹配到hash值后进行的操作,也就是我们上面定义的changePage函数。

3.在点击按钮的时候调用router.push({ path: "/student" })就可以改变url的hash值,值改变了就触发了window的hashchange事件,也就执行了我们定义好的changePage函数。


总结

这就是一个简单的hash路由的实现,示例不够完善,只是作为学习原理的一个参考。如有问题感谢指出。


巴斯光年
274 声望23 粉丝