前端如何實現hash路由

路由發展

之前的路由都是由後端實現的,根據url來從新載入頁面。可是近年來前端頁面變得愈來愈複雜致使服務器端壓力愈來愈大。天然出現瞭解決方案,經過url的改變,在不刷新頁面的狀況下,修改頁面內容,這就是本文將要介紹的前端路由。html


路由分類

前端路由的兩種實現方式:前端

  • 利用history對象實現前端路由
  • 監聽window對象的hashchange事件實現前端路由,就是本文重點介紹的hash路由

hash路由

何爲hashnode

  • 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函數。less

3.在點擊按鈕的時候調用router.push({ path: "/student" })就能夠改變url的hash值,值改變了就觸發了window的hashchange事件,也就執行了咱們定義好的changePage函數。dom


總結

這就是一個簡單的hash路由的實現,示例不夠完善,只是做爲學習原理的一個參考。若有問題感謝指出。ide

相關文章
相關標籤/搜索