码迷,mamicode.com
首页 > Web开发 > 详细

原生 js前端路由系统实现1

时间:2015-07-08 19:13:42      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:

在看了百度手机小说网站源码之后  突然兴起想自己实现一个基于网页hash技术的路由系统

源码 我放到oscgit上面了 地址: https://git.oschina.net/diqye/route.js

适用场景:

 局部刷新页面    通过ajax局部刷新页面会有一个问题就是 分享url或者刷新页面时不能记录 当前网页的状态  前端路由可解决这个问题

期望的路由:

   1  当访问网页 http://localhost/index.html 或者 http://localhost/index.html#   http://localhost/index.html#/ 会触发如下代码中的fn

         route.get(‘/‘,fn);  fn的参数 req: 请求的信息  next如果后面有匹配的路由 调用该函数会继续匹配后面的路由

   2 路径作为参数 当url改变为  http://localhost/index.html#2222/333 或者 http://localhost/index.html#/2222/333 期望把333传送给fn  当然路径中也支持*通配符

       

//number 只匹配数字
route.get(‘/2222/:number‘,function(req,next){
    //req.para的值为333 
});
//string 只匹配字符串
route.get(‘/2222/:string‘,function(req,next){
    //req.para的值为333 
});

  

 3 全局拦截器  这个主要是对扩展的考虑

route.use(function(req,next){
  //所有的路由变更都会经过此函数 如果不调用next函数路由不会往下匹配
    		console.log(‘1111‘);
    		next();
});


4 querystring 对象  当url为 http://localhost/index.html#?a=a&b=b  期望

route.get(‘/‘,function(req,next){
  //req.query的值为 {a:‘a‘,b:‘b‘}
});

  这个功能想通过拦截器来实现 比如

 

function querystring(req,next){
    		var query={};
    		//解析req.path 获取参数封装成对象 然后赋值给query

    		req.query=query;
    		next();
    	}
    	route.use(querystirng);



以上功能除了querystring 都实现了 关于路径匹配 还多加了俩个 支持 函数和正则  以下是代码  和测试代码 只测试了chrome浏览器 

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Documeddddnddddddt</title>
</head>
<body>
    <a href="#222/33/444">#222/33/444</a>
    <a href="#111">#111</a>
    <script type="text/javascript">

        var TYPE=(function(){
            var r={},types=[‘Arguments‘,‘Function‘,‘String‘,‘Number‘,‘Date‘,‘RegExp‘,‘Error‘,‘Null‘];
            for(var i=0,t;t=types[i++];){
                !function(t){
                    r[‘is‘+t]=function(obj){
                        return Object.prototype.toString.call(obj) === ‘[object ‘+t+‘]‘;
                    }
                }(t)
            }
            return r;
        })();
        //前端路由 本来打算写成一个函数,但路由对象只需要全局存在一个即可 并没有发现需要多个对象存在的场景
        var route=(function(){
            var p={
                //全局拦截器,本来想用链表来实现,但基于Javascript的特性用数组实现更加简单 和易用
                headUseFns:[],
                gets:[],
                type:{
                    ‘number‘:/^\d+$/,
                    ‘string‘:/^[^\/]+$/,
                    ‘date‘:/^[0-9]{6,6}$/
                }
            };
            function getPath(url){
                var path=url.split("#")[1];
                if(!path)return "/";
                if(path.charAt(0)!="/")path="/"+path;
                return path;
            }

            function use(fn){
                p.headUseFns.push(fn);
            }

            function hashchange(path){
                var req={path:path},hlen=p.headUseFns.length;
                if(hlen==0){
                    doother(req);
                    return;
                }
                //执行拦截器链
                !function intec(i){
                    if(i==hlen){
                        doother(req);
                        return;
                    }
                    p.headUseFns[i](req,function(){
                        intec(i+1);
                    });
                }(0);
            }

            function doother(req){
                var path=req.path,hlen=p.gets.length;
                var a=path.split(‘?‘);
                if(a[1])path=a[0];
                path=path.split(‘//‘).join(‘/‘);
                if(path.charAt(path.length-1)==‘/‘)path=path.substr(0,path.length-1);
                //执行拦截器链
                !function intec(i){
                    if(i==hlen){
                        return;
                    }
                    if(p.gets[i].match(path,req)){
                        p.gets[i].fn(req,function(){
                            intec(i+1);
                        });
                    }else{
                        intec(i+1);
                    }
                    
                }(0);
            }

            function get(context,fn){
                var match=null;
                if(TYPE.isFunction(context))match=context;
                else if(TYPE.isRegExp(context)){
                    match=function(path,req){
                        var para=context.exec(path);
                        if(para){
                            req.para=para;
                        }
                        return para;
                    }
                }else if(TYPE.isString(context)){
                    match=stringmatch(context);
                }
                var getter={
                    match:match,
                    fn:fn
                };
                p.gets.push(getter);
            }
            function stringmatch(context){
                var a=context.split(‘:‘),b=context.split(‘*‘);
                if(a.length==1&&b.length==1){
                    return function(path,req){
                        return path==context;
                    }
                }else if(a.length!=1){
                    var reg=p.type[a[1]];
                    if(reg==null)reg=new RegExp(a[1]);
                    return function(path,req){
                        var para=path.substr(a[0].length);
                        var r=path.indexOf(a[0])==0&&reg.test(para);
                        if(r)req.para=para;
                        return r;
                    }
                }else if(b.length!=1){
                    return function(path,req){
                        return path.indexOf(b[0])==0;
                    }
                }
            }
            function start(){
                window.onhashchange=function(){
                    var path=getPath(location.href);
                    hashchange(path);
                }
                var path=getPath(location.href);
                hashchange(path);
            }

            return {
                start:start,
                use:use,
                get:get
            }
        })();

        function querystring(req,next){
            var query={};
            //解析req.path 获取参数封装成对象 然后赋值给query 先不做

            req.query=query;
            next();
        }
        route.use(querystring);
        route.use(function(req,next){
            console.log(‘1111‘);
            next();
        });
        route.use(function(req,next){
            console.log(‘2222‘);
            next();
        });
        route.get(‘/*‘,function(req,next){
            console.log(‘/*‘,req);
            next();
        })
        route.get(‘/:number‘,function(req){
            console.log(‘/:number‘,req);
        })
        route.get(‘/:string‘,function(req){
            console.log(‘/:string‘,req);
        })
        route.get(‘/222/*‘,function(req,next){
            console.log(‘/222/*‘,req);
            next();
        });
        route.get(‘/222/33/444‘,function(req,next){
            console.log(‘/222/33/444‘,req);
            next();
        });
        route.get(‘/222/33/:number‘,function(req,next){
            console.log(‘/222/33/:number‘,req);
        });
        route.start();
    </script>
</body>
</html>

这一小段代码 有一些小bug 我会在后续博文过程中去 修复

原生 js前端路由系统实现1

标签:

原文地址:http://my.oschina.net/diqye/blog/476286

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!