前言
在前端单页面应用里面,路由是比较重要的部分,现有的路由系统从简易的director.js到backbone,react等内置路由,功能一步步增强。那么这些系统原理是什么呢,本文将分析并实现一份简易的路由,以阐述其工作原理。
简易路由实现
以hash做示范,其运行机制如下:
储存hash与对应的回调函数,以key,value的形式存入对象cache中
设置监听函数onhashchange监听url的hash变化
一旦hash变化,则遍历cache对象,将属性key做正则处理,生成对应的正则,再将其拿去和hash做正则匹配,匹配到后执行相应的value/回调函数
回调函数中执行渲染ui的代码,进而更新页面
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.html
<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>
代码地址
效果图
流程图
归纳
虽然本文实现比较简单,但很多框架的内部路由也是基于这种机制,只不过有基于对自身的特性做了一些优化。
最后
本文有什么不完善的地方,或者流程图有待改进的地方,敬请斧正。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。