router.js 3.28 KB
/**
 * Created by kenkozheng on 2015/7/16.
 * 利用backbone的路由语法,建立极简,适用于手机浏览器的路由
 * 增加了*号路由,等于backbone的defaultAction
 */
define(
    'mk7/router',
    [
    ],
    function() {
        
        var router = {
            init: function (map) {
                var defaultAction = map['*'];
                if(defaultAction){
                    router.defaultAction = defaultAction;
                    delete map['*'];
                }
                router.routes = map;
                init();
                onchange();
            },
            routes: {},
            defaultAction: null
        };

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

        /**
         * 引自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]*))?$');
        }

        /**
         * 这段判断,引用于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');
            }
        }

        return router;
    }
);