第6天 路由功能——params.js 插件开发
params.js 插件开发
params.js 中间件可以把:xxx路由解析出来的数据,保存到req.params中。但这个插件开发有些难度,原因是如何知道url和:xxx对应?首先就要知道那个路由器,然后还要解析出对应的url。越想越复杂。所以,我们需要修改App.js代码,这个功能集成到泛式路由部分。
首先,需要对pathRegexp.js模块进行修改,通过修改可以知道某个路由规则下的参数名称。例如 /about/:name/:age 要得到一个数组 ["name","age"];
pathRegexp.js 修改后的代码是:
module.exports = pathRegexp;
function pathRegexp(path) {
var paramNames = [];
path = path
// 这个方法用把 * 替换成正则表达式的 [0-9a-zA-Z\-_]* 形式。
// 上一节介绍了,这里用了 [0-9a-zA-Z\-_]* 目的是一种限定。
// 如果用 .* 那么 /article/:name 就会有个bug,/article/ok/abc 也是匹配的
// 这是因为 .* 匹配的话 ok/abc 也是匹配 .* 的,因为 / 也符合。
.replace(/((\*{1}(?=\/))|(\*{1}(?=$)))/g, "[0-9a-zA-Z\-_]*")
// 这个方法是把 :xxx 的形式替换成 [0-9a-zA-Z\-_]* 正则表达式形式。
// 这个方法还有个作用,就是例如:把 :name的,提取出 name ,并保存到paramNames数组中。
// 保存到paramNames中的目的是,当有匹配这个路由时,通过paramNames可以得到对应的值。
// 这也是为什么要采用 ([0-9a-zA-Z\-_]*) 的形式 ,而不是直接 [0-9a-zA-Z\-_]* 用这个,
// 因为 ([0-9a-zA-Z\-_]*) 形式是正则表达式组的形式,通过通过正则表达式的 RegExp.$1 ... $n
// 与paramNames就可得到参数名对应的值 ,例如:
// /article/:id 的如果url是 /article/id001 ,那么就有办法得到 id="id001",因为paramNames数组
// 现在是 ["id"] ,那么,/article/:id 由这个方法转换后,转换为 /^\/article\/([0-9a-zA-Z\-_]*)\/?$/
// 这个形式。通过 /^\/article\/([0-9a-zA-Z\-_]*)\/?$/g.test("/article/id001") 得到true。
// 当正则表达式调用了test方法,那么RegExp表达式类的静态值$1 $2 ... 就会重写!
// 那么,这里RegExp.$1值就是id001。而 paramNames[0] 的值是 id,这样就能得到
// id和对应的值。
// 具体实验代码如下:
// /^\/article\/([0-9a-zA-Z\-_]*)\/?$/g.test("/article/id001");
// console.log(RegExp.$1); // 打印出 id001
.replace(/(:(.*?(?=\/)))|(:(.*?(?=$)))/g,function () {
// arguments的第一个和最后两个参数,并不是我们想要的$1 ... $n的匹配值,
// 所以 len 是匹配的数量
var len = arguments.length - 3;
for (var i = 0; i < len; i++) {
var avg = arguments[i + 1];
// 由于正则嵌套分组,所以要判断匹配字符串是否有 " : " 前缀,
// 目的是得到 :name的name部分和 :age 的 age部分。
if (typeof avg === "string" && avg[0] !== ":") {
paramNames.push(avg);
}
}
return "([0-9a-zA-Z\-_]*)"
})
// 把 /article/:id/ 的转换为 /article/:id
.replace(/\/$/g, "")
// 把 / 转换为 \/ ,因为这是字符串形式,最后通过 new RegExp(path)
// 生成时,必须要经过这个转换。
.replace(/\//g, "\\\/")
var regexp = new RegExp("^" + path + "\\/?$");
regexp.paramNames = paramNames;
return regexp;
}paramNames这个数组中就储存着参数名称,然后直接赋值给regexp.paramNames = paramNames。下一步,要在App.js中做文章,把每次符合对应正则的请求url,解析出:xxx对应的值。
首先,我们要在App.js中的handle函数里,加入 req.params = {} 用于储存,代码如下:
function App(){
// request事件响应函数
function handle(req,res){
req.params = {};
}
}最后,要在 App.js 中的findHandle函数内做文章,看下面代码。
function findHandle(route_handles){
if(pass){
// 得到URL中对应 :XXX 的值,并保存在req.params中。
route_handle.route.paramNames.forEach(function(name,index){
req.params[name] = RegExp["$"+(index+1)];
})
handle = route_handle.handle;
break;
}
}
}通过这三个部分的代码,让stuwebfk框架具备了req.params特性。而本节题目是params.js插件,看来是错了,因为并没有建立params.js这个模块,而是为了实现这个功能,修改了 App.js 和 pathRegexp.js 。 这里有些JS语言相对高级的用法,稍后会在最后一节中,加以总结。
下面,通过视频的方式,演示此功能。
下面是测试代码:
var App = require("../..").App,
query = require("../..").query,
app = new App;
app.get("/about/:name/:age",function(req,res){
res.write("my name is "+req.params.name+"\n");
res.write("my age is "+req.params.age)
res.end();
})
app.listen(3000);现在的框架具备了req.query和req.params的属性,也是必须具备的,否则就无法实际开发。下一节对今天开发的一些代码做一下总结,这样可以跟深入的理解开发细节。
所有文章未经授权禁止转载、摘编、复制或建立镜像,违规转载法律必究。
举报邮箱:doramart@qq.com
推荐阅读
微信客服
微信公众号