1、引子

  最近学用director.js,那是相当的简单易学易使用。不过开始学的时候,搜搜过后,却没有发现相关的中文教程。于是决定硬啃E文,翻译备用的同时也当是给自己上课并加深对它的理解。

  director.js 的官方地址请点击 这里 查看,本教程内容也主要来自于这里。

2、director.js是什么

  director.js 按照我的理解就是客户端的路由注册/解析器,它在不刷新页面的情况下,利用“#”符号组织不同的URL路径,并根据不同的URL路径来匹配不同的回调方法。通俗点说就是什么样的路径干什么样的事情。

  director.js 适用于客户端浏览器以及node.js的服务器端应用,在两者的应用场景里调用方法仅有少量的不同。它非常适合用来开发不需要刷新的单页程序以及node.js应用。尤其单页程序,对于不想介入手机APP开发的同学,可以利用这个实现类似APP的应用程序。

  director.js 不依赖于任何其他的js库,例如jquery等。但是它又和jquery能很好的融合在一起进行使用。

  在本篇主要学习它在客户端的应用,node.js服务器端暂不讨论。

  

3、简单的开始

  上文简单提到: director.js 是通过“#”符号进行路径组织的,例如:

http://www.demo.com/#/show
http://www.demo.com/#/show/list
http://www.demo.com/#/show/single

  

  路由注册在URL里的体现是用“#”符号来标识路由的开始,再利用"/"分隔符(分隔符可自定义,后面会讲到)来定义路由片段。客户端路由其实就是通过URL来区分应用程序的不同状态,并且定义在不同的状态下应该做什么事情。当用户访问不同的URL时,director.js 会解析路由信息并告知应用程序需要做什么事情。

  路由格式具体可参考下图:

  下面是一个简单的例子:

<html>
<head>
<title>A Gentle Introduction</title>
<script src="/js/director.min.js"></script>
<script> var author = function () { console.log("author"); },
books = function () { console.log("books"); },
viewBook = function(bookId) { console.log("viewBook: bookId is populated: " + bookId); }; var routes = {
'/author': author,
'/books': [books, function() { console.log("An inline route handler."); }],
'/books/view/:bookId': viewBook
}; var router = Router(routes);
router.init(); </script>
</head>
<body>
<ul>
<li><a href="#/author">#/author</a></li>
<li><a href="#/books">#/books</a></li>
<li><a href="#/books/view/1">#/books/view/1</a></li>
</ul>
</body>
</html>

  

  和jquery一起使用的列子:

<html>
<head>
<meta charset="utf-8">
<title>A Gentle Introduction 2</title>
<script src="/js/jquery.min.js"></script>
<script src="/js/director.min.js"></script>
<script>
$('document').ready(function(){
var showAuthorInfo = function () { console.log("showAuthorInfo"); },
listBooks = function () { console.log("listBooks"); },
allroutes = function() {
var route = window.location.hash.slice(2),
sections = $('section'),
section;
if ((section = sections.filter('[data-route=' + route + ']')).length) {
sections.hide(250);
section.show(250);
}
}; var routes = {
'/author': showAuthorInfo,
'/books': listBooks
}; var router = Router(routes); router.configure({
on: allroutes
});
router.init();
});
</script>
</head>
<body>
<section data-route="author">Author Name</section>
<section data-route="books">Book1, Book2, Book3</section>
<ul>
<li><a href="#/author">#/author</a></li>
<li><a href="#/books">#/books</a></li>
</ul>
</body>
</html>

  下面将会就director.js 客户端相关的API进行详细的说明。

4、初始化及路由注册

  director.js 的主要对象是Router对象,构造方法如下:

var router = new Router(routes);

  

  构造方法中传入的routes参数是一个路由表对象,它是一个具有键值对结构的对象,路由允许多层的嵌套定义。

  键值对的键对应URL中传入的路径,一般一个键对应按分隔符切割后的某一部分;而键值对的值则对应该路径需要触发的回调函数名,可以传入一个或多个函数名,传入多个函数名时请使用数组对象。一般来说,回调函数要在路由表对象使用前先声明,否则js会报错。

  另外,回调函数除非特殊情况,一般不推荐使用匿名函数,请尽量先声明后使用。

  var routes = {
'/dog': bark,
'/cat': [meow, scratch]
};

  上面例子中,对应的URL分别为:#/dog 和 #/cat

  

  声明Router对象后,需要调用init()方法进行初始化,如下:

var routes = {
'/dog': bark,
'/cat': [meow, scratch]
}; var router = Router(routes);
router.init();

5、路由的即时注册

  当我们在开发一些规模比较大的应用的时候,一般做不到一开始就将需要的路径和它对应的回调函数都预先准备好。很多时候,我们都是在做到某一功能时,或者是开发一些独立性比较强耦合度比较低的模块时,才知道我们需要什么样的路径和回调函数。这个时候我们就需要实时注册路由的功能了。

  director.js 通过“on”方法,提供对即时注册功能的支持,示例如下:

var router = Router(routes).init();
....
router.on('/rabbit', function(){
  ...
})

6、路由事件

  路由事件是路由注册表中一个有固定命名的属性,是指当路由方法router.dispatch()被调用时,路由匹配成功的时定义的需要触发的回调方法(允许定义多个回调方法)。上文即时注册功能里的"on"方法就是一个事件。具体信息如下:  

  • on :当路由匹配成功后,需要执行的方法
  • before:在触发“on”方法之前执行的方法

  仅在客户端有效的方法:

  • after:当离开当前注册路径时,需要执行的方法
  • once: 当前注册路径仅执行一次的方法
var routes = {
"/about/:id": {
before: function (id) { alert("direct to : /Home/About/" + id); },
on: function (id) { window.location = "/Home/About/" + id; }
};

  *以上示例中使用了匿名函数,仅因为做为示例比较方便,不推荐这种使用方式

7、配置参数

  director.js 通过配置一些可选项的参数从而提升Router对象的灵活性。而这些参数的设置需要通过router.configure()方法实现。

var router = new director.Router(routes).configure(options);

  具体的配置参数有:

  • recurse:控制路由递归触发方式的参数,可选值为"forward","backward"和"false",客户端的默认值是"false",而服务端的默认值是"backward"
  • strict:当值为"false"时,路径允许以"/"结尾(也可以是其他自定义的分隔符);默认值是"true",说明默认不允许路径以"/"结尾
  • async:同步异步控制器,值为"ture","false",默认值为"false"
  • delimiter:路由分隔符,默认值为"/"
  • notfound:当路由方法router.dispatch()被调用时,没有匹配到任何路由时触发的方法
  • on:当路由方法router.dispatch()被调用时,任何一个路由匹配成功后都需要执行的方法;与上文路由事件中的“on”事件的区别类似于全局和局部的概念,路由表中仅针对当前注册的路由;而configure方法中的"on"则针对全局的所有路由
  • before:当路由方法router.dispatch()被调用时,当任何一个路由匹配成功并在"on"执行之前需要执行的方法;与上文路由事件中的 “before” 事件的区别同上

  仅在客户端有效的参数:

  • resource:用来进行回调函数绑定的基于字符串的对象。使用该参数能实现回调函数的延迟绑定(原词是 "late-binding",后面有相关的详细说明)
  • after:当给定的路径不再是当前激活的路径时触发的方法,可以理解为离开当前路径后触发的方法;与上文路由事件中的 “after” 事件的区别同上

  *以上的配置参数在后面均有详细的讲解

  *另外仅在客户端起效的参数还有html5history和run_handler_in_init,这两个参数是与html5相关,暂时也不讨论

8、URL匹配

  在路由事件那一节的示例里,有这么一个路由表达式"/about/:id",其中":"后面定义的部分表示实际路径对应的这部分是传入回调函数的参数,例如"#/about/5"中,5就是id参数的值。参数的匹配还可以用嵌套的方式来定义:

var router = Router({
'/about': {
'/:id': {
on: function (id) { console.log(id) }
}
}
});

  在实际应用的过程中,我们的路由可能会变得非常复杂,像"/about/:id"这样简单的表达式并不能满足我们的需求。而director.js 支持利用正则表达式来匹配复杂的路由名称,匹配到的值会作为参数传给回调函数,例如:

var router = Router({
'/hello': {
'/(\\w+)': {
on: function (who) { console.log(who) }
}
}
});

  当URL传入'#/hello/world',则回调函数的who=world

  支持更为复杂的多参数的传递:

var router = Router({
'/hello': {
'/world/?([^\/]*)\/([^\/]*)/?': function (a, b) {
console.log(a, b);
}
}
});

  当URL传入'#/hello/world/johny/appleseed',则回调函数的a=johny,b=applesee

9、路由的递归匹配

  全局配置中的recurse参数决定了路径在路由表中的命中方式以及命中顺序。命中方式包括递归命中和精确命中;命中顺序包括正序,反序和中断。

  当参数设定为“forward、backward”时,表明路由的命中方式是递归命中,并按照规定的顺序命中,forward为正序,backward为反序。路由如果定义了多个路由片段,则它们对应的回调函数均可命中,也就是说一个路径可以命中多个函数。

  当没有特别指定该参数的值时(即默认值"false"),则标明路由的命中方式为精确命中,需要完全匹配整个路径后才可以命中,也就是说一个路径只能命中一个函数。

  当URL传入"#/dog/angry"时,路由表注册如下:

  var routes = {
'/dog': {
'/angry': {
on: growl
},
on: bark
}
};

  

  当没有指定递归匹配的方式时,仅命中growl方法。

  当指定递归匹配参数的值为backward时,首先命中growl方法,然后再命中bark方法,按照路径的注册顺序反序命中。如下:

var router = Router(routes).configure({ recurse: 'backward' });

  当指定递归匹配参数的值为forward时,首先命中bark方法,然后再命中growl方法,按照路径的注册顺序正序命中。如下:

var router = Router(routes).configure({ recurse: 'forward' });

  当指定了递归匹配参数后,如果命中的函数中使用了"return false;"的语句返回,则会中断递归命中,直接返回。如下:

  var routes = {
'/dog': {
'/angry': {
on: function() { return false; }
},
on: bark
}
};
var router = Router(routes).configure({ recurse: 'backward' });

  无中断时,首先会命中angry下的方法,然后命中bark方法;但是在使用return false语句之后,执行完angry命中的方法后将不再递归命中别的方法(bark)。

10、资源参数

  全局配置中的resource参数仅在客户端应用中可用,它是一个文本对象,其中的文本属性值主要用来定义路由匹配命中后的回调方法名。它可以为程序提供更好的封装性,以便更好的进行结构设计。

  var router = Router({
'/hello': {
'/usa': 'americas',
'/china': 'asia'
}
}).configure({ resource: container }).init(); var container = {
americas: function() { return true; },
china: function() { return true; }
};

  示例中,container对象定义在路由对象之后,我觉得这个就是之前说的“延迟绑定”功能。因为路由的回调函数绑定必须遵守先声明后使用的方法,这个示例明显是先使用后声明。但是我测试了一下,这样做会报错,还是不能改变先声明后使用的顺序。因此延迟绑定的意思我还没真正搞清楚。

11、小结

  director.js 在客户端应用的中文简明教程暂时就是这些,有了这些知识做一个简单的CRUD的DEMO程序是完全没问题了。不过我在做这个DEMO的过程中,觉得还是没有体会到director.js 使用的精髓。因为我在命中后调用了AJAX方法,我的问题是既然已经用了AJAX方法,由何必用director.js 呢?感觉还是得再详细看一下《bootstrap + requireJS+ director+ knockout + web API = 一个时髦的单页程序》这篇文章和它的示例才能体会director.js 的精髓。也感谢该文章作者的分享。

  以后有时间再研究和补齐服务端应用的教程,以及在html5应用下的几个配置参数和方法。需要了解更详细信息的同学还是可以去它的 官方地址 啃E文。

  Over!

director.js:客户端的路由---简明中文教程的更多相关文章

  1. director.js实现前端路由

    注:director.js的官网 https://github.com/flatiron/director director.js是什么? 理解:前端的route框架,director.js客户端的路 ...

  2. Groovy中文教程(链接收藏)

    学习Gradle前,需要有一个Groovy语言的基础,以免被Groovy的语法困扰,反而忽略了Gradle的知识.这里有一个Groovy的简明中文教程文档,可以快速学习Groovy的一些语法:http ...

  3. director.js教程

    directive.js 初始化和注册路由 director.js 的主要对象是Router对象,构造方法如下: var router = new Router(routes); //routes为路 ...

  4. Google Analytics统计代码GA.JS中文教程

    2010-12-06 11:07:08|  分类: java编程 |  标签:google  analytics  ga  js  代码  |举报|字号 订阅     Google Analytics ...

  5. 《zw版·Halcon-delphi系列原创教程》 Halcon分类函数·简明中文手册 总览

    <zw版·Halcon-delphi系列原创教程> Halcon分类函数·简明中文手册 总览 Halcon函数库非常庞大,光HALCONXLib_TLB.pas文件,源码就要7w多行,但核 ...

  6. jQuery.qrcode.js客户端生成二维码,支持中文并且可以生成LOGO

    描述: jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码.此插件是能够独立使用的,体积也比较         ...

  7. Python消息队列工具 Python-rq 中文教程

    原创文章,作者:Damon付,如若转载,请注明出处:<Python消息队列工具 Python-rq 中文教程>http://www.tiangr.com/python-xiao-xi-du ...

  8. WebPack 简明学习教程

    WebPack 简明学习教程 字数1291 阅读22812 评论11 喜欢35 WebPack是什么 一个打包工具 一个模块加载工具 各种资源都可以当成模块来处理 网站 http://webpack. ...

  9. webstorm的中文教程和技巧分享

    webstorm是一款前端javascript开发编辑的神器,此文介绍webstorm的中文教程和技巧分享.webstorm8.0.3中文汉化版下载:百度网盘下载:http://pan.baidu.c ...

随机推荐

  1. Excel 导入到Datatable 中,再使用常规方法写入数据库

    首先呢?要看你的电脑的office版本,我的是office 2013 .为了使用oledb程序,需要安装一个引擎.名字为AccessDatabaseEngine.exe.这里不过多介绍了哦.它的数据库 ...

  2. OleDB Destination 用法

    第一部分:简介 OleDB Destination component 是将数据流load 到destination,共有5种Data Access Mode,一般的Destination compo ...

  3. 让虚拟机的软盘盘符不显示(适用于所有windows系统包括Windows Server)

  4. SQL Server 解读【已分区索引的特殊指导原则】(3) - 非聚集索引分区

    一.前言 在MSDN上看到一篇关于SQL Server 表分区的文档:已分区索引的特殊指导原则,如果你对表分区没有实战经验的话是比较难理解文档里面描述的意思.这里我就里面的一些概念进行讲解,方便大家的 ...

  5. C#设计模式系列:原型模式(Prototype)

    1.原型模式简介 1.1>.定义 原型模式(Prototype)用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象. 1.2>.使用频率 中 1.3>.原型模式应用 首先 ...

  6. Visulalize Boost Voronoi in OpenSceneGraph

    Visulalize Boost Voronoi in OpenSceneGraph eryar@163.com Abstract. One of the important features of ...

  7. UWP开发之Mvvmlight实践三:简单MVVM实例开发(图文详解付代码)

    在做MVVM各种框架对比之前,我觉得有必要先自己做一个简单的MVVM实现案例比较好,这样就可以看到自己实现的时候有那些不方便的地方.而各种框架又是怎么解决我们这些麻烦的. 案例介绍:用户登录画面,没有 ...

  8. EntityFramework 7 Linq Contains In 奇怪问题(已修复)

    问题说明: 博客问题纪录 Use EF7, Linq Contains In is error. EF7 Code Commit adding (client side) support for Co ...

  9. Visual Studio Code 智能提示文件

    Visual Studio Code 开发前端和node智能提示 visual studio code 是一个很好的编辑器,可以用来编写前端代码和nodejs. 我很喜欢使用VSC,现在流行框架对VS ...

  10. chrome扩展程序开发

    首先,明确两个概念的区别:chrome扩展程序和Web Apps.具体参考:http://www.chromi.org/archives/10106 本文只讨论chrome扩展程序. 最好的开发教程莫 ...