SPA学习之 - 路由插件(crossroads.js)

Crossroads.js是一个受Rails, Pyramid, Django, CakePHP等基于路由/分发(Route/Dispatch)方式处理路由的后端MVC框架启发的一套js专业路由库。它能够直接解析传入的字符串并根据相应的规则来过滤和验证路由,然后再执行下一步的操作。

A duck can walk, fly and swim, but he can’t do any of these things well…

crossroads.js是一个独立的库功能十分强大和灵活,而且职责单一、目标定位清晰。如果在项目中应用适当不尽可以减少代码的复杂度,同时也可以通过在页面中使用hash路由方式来抽象页面路径和服务器请求。当然在开发SPA页面过程中,如果我们不使用backbone, Angular等类似的MVC库来开发SPA的话,它是一个相当不错的选择。当然还有一个router.js也是一个相当不错的独立路由插件,后续我会专门介绍其用法。类似的一些处理路由的js库还有:urianchor(在《单页Web应用:JavaScript前端到后端》这本书中有介绍其使用方法)、jquery-hashchangepathjs等。

crossroads.jsMiller Medeiros开发, 它的使用不依赖于第三方库,内部仅仅只依赖于作者另一个js库signals.js:将ActionScript一个开源库as3-signals移植到了js。

js信号机制可以参考阮一峰老师的日志”Javascript异步编程的4种方法“。

由于crossroads.js只定义了路由配置和规范,当页面监有路由请求信号发出时crossroads.js会监听到信号,同时浏览器地址栏中的地址栏也会指向目标地址,但还需要一个处理页面hashchange事件的库。这里可以使用作者开发的库hasher.js或者使用history.js来处理’hashchange’事件。

下面我将和大家一起来了解crossroads.js的用法:

一、基本使用方法

首先,先来看几个常见的URL地址,以点名时间的路由为例:

// 新品首页
http://www.demohour.com/projects/latest

// 新品筛选
http://www.demohour.com/projects/latest?attribute=online&category=927151&sort=2

// 项目详情页面
http://www.demohour.com/projects/354263

 

点名时间产品分为’新品’、’特卖’和’预售’,那么对应的路由定义可以这样:

// 这里`projectsType`值为: ‘latest‘, ‘sell‘, ‘presell‘
/projects/{projectsType}

 

相应的新品筛选带参地址定义如下:

/projects/latest?attribute={attributeValue}&category={projectsId}&sort={sortord}

 

地址中对应参数值定义如下:

// 分类
attributeValue = {
    ‘927219‘: ‘通讯数码‘,
    ‘927151‘: ‘家居生活‘,
    ‘927158‘: ‘智能穿戴‘,
    ‘927218‘: ‘影音娱乐‘,
    ‘927162‘: ‘出行定位‘,
    ‘927250‘: ‘办公相关‘,
    ‘927220‘: ‘其它‘
};

// 排序
sortord = {
    ‘0‘: ‘默认排序‘,
    ‘1‘: ‘评分最高‘,
    ‘2‘: ‘评价最多‘,
    ‘3‘: ‘收藏最多‘,
    ‘4‘: ‘浏览最多‘
}

 

那么我们如何在SPA页面中通过crossroads.js实现以上路由的定义呢? 首先引入相应的js库:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SPA学习之 - 路由插件(crossroads.js)</title>
    <script src="js/jquery-1.11.2.min.js"></script>
    <script src="js/signals.min.js"></script>
    <script src="js/hasher.min.js"></script>
    <script src="js/crossroads.min.js"></script>
</head>
<body>
    <h1>SPA学习之 - 路由插件(crossroads.js)</h1>

    <script>
        $(function() {
            // 这里输入内容
        });
    </script>
</body>
</html>

 

crossroads.js中定义一个路由可以使用crossroads.addRoute(pattern, [handler], [priority]):Route方法,可以接受三个参数:

  • parttern: 对应路由规则,可以为字符串或者正则表达式
  • handler: 可选参数,当监听到路由时的处理方法
  • priority: 可选参数,定义路由在路由队列中的优先级

从函数的定义中可以看出其返回一个Route对象,后面会讲解Route对象相关属性和方法。在crossroads.js中我们可以通过以下两种方式定义一个路由:

// 方式一:定义路由时同时定义操作
crossroads.addRoute(‘projects/{projectsType}‘, function(projectsType) {
     console.log(projectsType);
});

// 方式二:只定义一个路由,返回一个`Route`对象
var projectsRoute = crossroads.addRoute(‘projects/{projectsType}‘);

// 这里通过`Route.matched`信号来处理操作
 projectsRoute.matched.add(function(projectsType) {
    console.log(projectsType);
});

 // 通过`crossroads.parse()`方法来解析一个路由
crossroads.parse(‘/projects/sell‘); // 输出: sell

 

在上面分析 点名时间 路由时,我们看到带查询参数的新品筛选地址, 在crossroads.js中可以通过对每个分组名前添加”?“(例如:{?foo}、:?bar:)来实现。

crossroads.addRoute(‘projects/{projectsType}/{?filter}‘, function(projectsType, filter) {
    console.log("项目类型:" + projectsType + ‘;\n‘ + "排序:" + filter.sort + ‘;\n‘ + "项目ID:" + filter.category + ‘;\n‘ + "分类:" + filter.attribute + ‘;‘);
});

crossroads.parse(‘projects/latest?attribute=online&category=927151&sort=2‘);

/*
 * 输出结果
 * ================
 *  项目类型:latest;
 *  排序:2;
 *  项目ID:927151;
 *  分类:online;
 * ================
 */

 

解析后所有匹配的值会被转换到一个对象中,默认情况下crossroads.js不会关心crossroads.parse()中传入的数据类型,传入的数字也会当成字符串处理。如果设置crossroads.shouldTypecast = ture, 那么会对处理后的对象值做出相应的类型判断。

crossroads.addRoute(‘projects/{projectsType}‘, function(projectsType) {
    console.log(projectsType);
    console.log(typeof projectsType);
});

crossroads.parse(‘/projects/sell‘); // 输出: sell和string
crossroads.parse(‘/projects/12323‘); // 输出: 12323和string

// 将对象类型检查开启
crossroads.shouldTypecast = true;

crossroads.parse(‘/projects/sell‘); // 输出: sell和string
crossroads.parse(‘/projects/12323‘); // 输出: 12323和number

 

在定义路由表达式时也可以通过用”::“包含一个字符或正则来实现可选路由(optional segments):

crossroads.addRoute(‘foo/:bar:/:far:‘, function(bar, far) {
    console.log(bar + " " + far);
});

crossroads.parse(‘foo‘); // undefined undefined
crossroads.parse(‘foo/abc‘); // abc undefined
crossroads.parse(‘foo/abc/xyz‘); // abc xyz

 

如果需要更多的可选路由(在其官网中称为:’rest’ segments),而且长度不确定,那么可以通过在分组尾部以’*’结尾来实现。

crossroads.addRoute(‘foo/:bar*:‘, function(bar) {
    console.log(bar);
});

crossroads.parse(‘foo‘); // undefined
crossroads.parse(‘foo/abc‘); // abc
crossroads.parse(‘foo/abc/xyz‘); // abc/xyz
crossroads.parse(‘foo/abc/xyz/123‘); // abc/xyz/123

 



在路由解析过程中,如果同一个地址能够被多个规则解析,那么可以通过指定crossroads.addRoute()第三个参数来提升优先级
/* 默认情况下按照声明先后顺序解析 */
crossroads.addRoute("bar/{lorem}", function(lorem) {
    console.log(lorem);
});
crossroads.addRoute("bar/{lorem}/:date:", function(lorem, date) {
    console.log(lorem + ‘ : ‘ + date);
});

crossroads.parse("bar/1"); // 1
crossroads.parse("bar/abc"); // abc
crossroads.parse("bar/abc/2015-3-11"); // abc : 2015-3-11

/* 下面通过设置优先级来改变默认解析顺序 */

// 默认情况下优先级为`0`
crossroads.addRoute("bar/{lorem}", function(lorem) {
    console.log(lorem);
}, 0);
// 指定第二个路由优先级为`1`
crossroads.addRoute("bar/{lorem}/:date:", function(lorem, date) {
    console.log(lorem + ‘ : ‘ + date);
}, 1);

crossroads.parse("bar/1"); // 1 : undefined
crossroads.parse("bar/abc"); // abc : undefined
crossroads.parse("bar/abc/2015-3-11"); // abc : 2015-3-11

 


crossroads.js既然能够创建路由,当然也有移除路由对应的方法:crossroads.removeRoute(route)以及crossroads.removeAllRoutes()

// 路由一
var a = crossroads.addRoute("foo/{bar}", function(bar) {
    console.log("第一个路由:" + bar);
});

// 路由二
crossroads.addRoute("bar/{lorem}", function(lorem) {
    console.log("第二个路由:" + lorem);
});

// 路由三
crossroads.addRoute("lorem/{ipsum}", function(ipsum) {
    console.log("第三个路由:" + ipsum);
});

crossroads.parse(‘foo/route1‘); // 第一个路由:route1
crossroads.parse(‘bar/route2‘); // 第二个路由:route2
crossroads.parse(‘lorem/route3‘); // 第三个路由:route3
console.log(crossroads.getNumRoutes()); // 3

// 移除路由一
crossroads.removeRoute(a);

// 第一个路由已从路由队列中移除了,不再接受解析
crossroads.parse(‘foo/route4‘);
crossroads.parse(‘bar/route5‘); // 第二个路由:route5
crossroads.parse(‘lorem/route6‘); // 第三个路由:route6
console.log(crossroads.getNumRoutes()); // 2

// 移除所有路由
crossroads.removeAllRoutes();

// 下面三个解析都没有任何作用,因为当前没有可解析的路由
crossroads.parse(‘foo/route7‘);
crossroads.parse(‘bar/route8‘);
crossroads.parse(‘lorem/route9‘);
console.log(crossroads.getNumRoutes()); // 0

 

注意在上面示例中,由于crossroads.removeRoute()需要一个Route对象作为参数,所以最好以第二种方式来定义一个路由规则,同时也方便路由统一配置和管理。crossroads.getNumRoutes()方法用于获取当前路由队列中路由数量。

未完待续。。。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。