一个类似backbone路由的纯净route ( 前端路由 客户端路由 backbone路由 )

大家用backbone、angular,可能都习惯了内置的路由,这两个框架的路由都是非常优秀的,强大而简单。

客户端(浏览器)路由原理其实比较简单,其实就是监听hash的变化。

在之前的架构探讨中,说到director.js这个路由类库不好使,那么,在这一篇,我们尝试自行实现一个简洁而且非常好使的路由类库。

原理先介绍,无非几个步骤:

  • 建立配置表(字符串路径和函数的映射)
  • 监听路由(onhashchange)
  • 处理路由变化,跟配置表的路径做匹配
    • 路径转化为正则表达式
    • 正则exec,匹配+抽取参数

其中难点就在于路径转化为正则表达式,director没做好就是这一步,而backbone则做得非常非常强大,那么我们可以尝试把backbone这一块代码抠出来。

路由表:

    var Route = root.Route = {
        init: function (map) {
            var defaultAction = map['*'];
            if(defaultAction){
                Route.defaultAction = defaultAction;
                delete map['*'];
            }
            Route.routes = map;
            init();
            onchange();
        },
        routes: {},
        defaultAction: null
    };

监听路由变化:

    /**
     * 这段判断,引用于director:https://github.com/flatiron/director
     */
    function init(){
        if ('onhashchange' in window && (document.documentMode === undefined
            || document.documentMode > 7)) {
            // At least for now HTML5 history is available for 'modern' browsers only
            if (this.history === true) {
                // There is an old bug in Chrome that causes onpopstate to fire even
                // upon initial page load. Since the handler is run manually in init(),
                // this would cause Chrome to run it twise. Currently the only
                // workaround seems to be to set the handler after the initial page load
                // http://code.google.com/p/chromium/issues/detail?id=63040
                setTimeout(function() {
                    window.onpopstate = onchange;
                }, 500);
            }
            else {
                window.onhashchange = onchange;
            }
            this.mode = 'modern';
        } else {
            throw new Error('sorry, your browser doesn\'t support route');
        }
    }

处理路由变化,先拼凑正则表达式:

    /**
     * 引自backbone,非常牛逼的正则
     * @param route
     * @returns {RegExp}
     */
    function getRegExp(route){
        var optionalParam = /\((.*?)\)/g;
        var namedParam    = /(\(\?)?:\w+/g;
        var splatParam    = /\*\w+/g;
        var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
        route = route.replace(escapeRegExp, '\\$&')
            .replace(optionalParam, '(?:$1)?')
            .replace(namedParam, function(match, optional) {
                return optional ? match : '([^/?]+)';
            })
            .replace(splatParam, '([^?]*?)');
        return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
    }

从原来的:module2/:name变成标准的正则表达式,个中奥妙大家自行顿悟

循环匹配:

    function onchange(onChangeEvent){
        var newURL = onChangeEvent && onChangeEvent.newURL || window.location.hash;
        var url = newURL.replace(/.*#/, '');
        var found = false;
        for (var path in Route.routes) {
            var reg = getRegExp(path);
            var result = reg.exec(url);
            if(result && result[0] && result[0] != ''){
                var handler = Route.routes[path];
                handler && handler.apply(null, result.slice(1));
                found = true;
            }
        }
        if(!found && Route.defaultAction){
            Route.defaultAction();
        }
    }

然后。。。做个简单的测试:

<script src="libs/backbone-route.js"></script>
<script>

    Route.init({
        'module1': function(){
            console.log(1);
        },
        'module2/:name/:age': function(){
            console.log(2, arguments);
        },
        'module3(/:name)(/:age)': function(){
            console.log('3', arguments);
        },
        '*': function(){
            console.log(404);
        }
    });
</script>

本文代码:https://github.com/kenkozheng/HTML5_research/tree/master/backbone-route

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏NetCore

复杂而艰辛的重构之路--起步

你有没有试过,当你踏入一个新的公司,看到了几千几万几十万代码的时候,那种崩溃的感觉? 代码多不可怕,怕的是代码的可读性、维护性、扩展性是如此之差,这时候该怎么办...

1889
来自专栏日常学python

用Python代码来下载任意指定网易云歌曲

前两天教了大家如何在控制台上找到真实的mp3播放地址,但是不可以下载付费的,因为只能下载可播放的歌曲。至于怎样下载付费网易云音乐,还是开个会员吧,要知道免费是最...

901
来自专栏web前端教室

我在工作中的常用代码管理

说是管理其实就是把常用的一些JS方法,自己保存下来,这样的以后的工作中可以比较方便的使用。 哪些方法可以、或是说值得保存呢?(偏见啊)我自己的主观看法就是一些功...

1785
来自专栏FreeBuf

深入分析IE地址栏内容泄露漏洞

? 前言 在本文中,我们探讨的对象是IE浏览器,尽管该浏览器略显老态,但是其用户还是很多的,所以不容忽视。我最近对MSRC感到很欣喜,因为他们正在将工作重心移...

23010
来自专栏灯塔大数据

技术 | Python从零开始系列连载(十六)

那什么是模块呢?简单的讲,就是一些包装好的内容,当你要用到一些操作在这个模块中时,你就先要导入它

882
来自专栏纯洁的微笑

小明历险记:规则引擎Drools教程一

893
来自专栏更流畅、简洁的软件开发方式

三层架构之我见 —— 不同于您见过的三层架构。

       我从02年开始了编程的工作,开始接触一些简单的网站,下半年写了个小的自助建站程序(asp和asp.net),比较简陋没有使用。03年开始正式做网站...

1777
来自专栏IMWeb前端团队

Unix Pipes to Javascript Pipes

本文作者:IMWeb 杨文坚 原文出处:IMWeb社区 未经同意,禁止转载 Unix Pipes Unix管道扫描稿 ? 简单样例: $ ne...

18110
来自专栏前端那些事

同步、异步、回调执行顺序之经典闭包setTimeout分析

聊聊同步、异步和回调 同步,异步,回调,我们傻傻分不清楚, 有一天,你找到公司刚来的程序员小T,跟他说:“我们要加个需求,你放下手里的事情优先支持,我会一直等你...

22810
来自专栏Java技术

【面试题】2018年最全Java面试通关秘籍第五套!

注:本文是从众多面试者的面试经验中整理而来,其中不少是本人出的一些题目,网络资源众多,如有雷同,纯属巧合!禁止一切形式的碰瓷行为!未经允许禁止一切形式的转载和复...

1061

扫码关注云+社区