簡易的前端路由實現

前言

在前端單頁面應用裏面,路由是比較重要的部分,現有的路由系統從簡易的director.js到backbone,react等內置路由,功能一步步加強。那麼這些系統原理是什麼呢,本文將分析並實現一份簡易的路由,以闡述其工做原理。css

簡易路由實現

以hash作示範,其運行機制以下:html

  • 儲存hash與對應的回調函數,以key,value的形式存入對象cache中前端

  • 設置監聽函數onhashchange監聽url的hash變化react

  • 一旦hash變化,則遍歷cache對象,將屬性key作正則處理,生成對應的正則,再將其拿去和hash作正則匹配,匹配到後執行相應的value/回調函數git

  • 回調函數中執行渲染ui的代碼,進而更新頁面github

router.js瀏覽器

function Router() {
    this.cache = {};
    //將url/callback 以key/value形式儲存在cache內
    this.on = function (key, value) {
        var cache = this.cache;
        cache[key] = value;
    };
    //匹配hash對應的回調函數,並觸發
    this.trigger = function (hash) {
        var cache = this.cache;
        for (var r in cache) {
            var reg = this.initRegexps(r);
            if (reg.test(hash)) {
                var callback = cache[r] || function () {
                    };
                var params = this.getParams(reg, hash);
                callback.apply(this, params);
            }
        }

    };
    //初始化 添加監聽瀏覽器hashchange 以及dom loaded函數
    this.init = function () {
        window.addEventListener('hashchange', function () {
            var hash = location.hash.slice(1);
            router.trigger(hash);
        });
        window.addEventListener('load', function () {
            var hash = location.hash.slice(1) || 'default';
            router.trigger(hash);
        })
    };
    /**
     *將cache內的key 作正則處理,並返回
     * 第一個正則 匹配諸如/,.+-?$#{}[]] 關鍵字  並在關鍵字前面加轉譯字符\
     * 第二個正則 匹配() 標示()內部內容無關緊要
     * 第三個正則 匹配: 在/後面能夠由接受任意字符,直到遇到下一個/
     * 第四個正則 匹配* 在*後面能夠由接受任意字符
     */
    this.initRegexps = function (route) {
        route = route.replace(/[/,.+\-?$#{}\[\]]/g, '\\$&')
            .replace(/\((.*?)\)/g, '(?:$1)?')
            .replace(/(\/\w?:\w+)+/g, '\/([^/]+)')
            .replace(/\*\w*/g, '([^?]*?)');

        return new RegExp('^' + route + '$');
    };

    //將匹配的正則返回,爲回調函數提供參數
    this.getParams = function (reg, hash) {
        return reg.exec(hash).slice(1);
    }
}

index.htmlapp

<style>
    .test {
        width: 200px;
        height: 200px;
        color:white;
    }
</style>

<div>
    <a href="#/aaaa/bcd">hash=aaaa/bcd 匹配/aaaa/:id</a>
</div>
<div>
    <a href="#/bbbb">hash=bbbb 匹配/bbbb(/:name)</a>
</div>
<div>
    <a href="#/bbbb/ddd">hash=bbbb/ddd 匹配/bbbb(/:name)</a>
</div>
<div>
    <a href="#/cccc/s/d">hash=cccc/s/d 匹配cccc/*</a>
</div>
<div class="test">
</div>

<script>
        var router = new Router();
        var test = $('.test');
        router.on('/', function () {
            test.css('background-color', 'green').css('color','white').html('我是綠色');
        })
        router.on('/aaaa/:id', function (id) {
            console.log(id);
            test.css('background-color', 'red').css('color','white').html('我是紅色');
        })
        router.on('/bbbb(/:name)', function (name) {
            console.log(name);
            test.css('background-color', 'yellow').css('color','red').html('我是黃色');
        })
        router.on('/cccc/*', function (x) {
            console.log(x);
            test.css('background-color', 'black').css('color','white').html('我是黑色');
        })
        router.init();
</script>

代碼地址

點擊查看本文完整代碼框架

效果圖

圖片描述

流程圖

圖片描述

概括

雖然本文實現比較簡單,但不少框架的內部路由也是基於這種機制,只不過有基於對自身的特性作了一些優化。dom

最後

本文有什麼不完善的地方,或者流程圖有待改進的地方,敬請斧正。

相關文章
相關標籤/搜索