全面解析JavaScript的Backbone.js框架中的Router路由


Posted in Javascript onMay 05, 2016

Backbone 中的 Router 充当路由的作用,控制 URL 的走向,当在 URL 中使用 # 标签时生效。
定义 Router 至少需要一个 Router 和一个函数来映射特定的 URL,而且我们需要记住,在 Backbone 中,# 标签后的任意字符都会被 Router 接收并解释。
下面我们来定义一个 Router:

<script>
 var AppRouter = Backbone.Router.extend({
  routes: {
   "*actions": "defaultRoute" // 匹配 http://example.com/#anything-here
  }
 });
 // 实例化 Router
 var app_router = new AppRouter;

 app_router.on('route:defaultRoute', function(actions) {
  alert(actions);
 })

 // 打开 Backbone 的历史记录
 Backbone.history.start();
</script>

现在,我们就定义好了一个 Router 了,但此时 Router 并未匹配特定的 URL,接下来我们开始详细讲解 Router 是如何工作的。

动态路由选择
Backbone 允许你定义带有特定参数的 Router。例如,你可能希望通过一个特定的 id 接收一个 post,比如这样一个 URL:"http://example.com/#/posts/12",一旦这个 Router 被激活,你就可以取得一个 id 为12的 post。接下来,我们就来定义这个 Router:

<script>
 var AppRouter = Backbone.Router.extend({
  routes: {
   "posts/:id": "getPost",
   "*actions": "defaultRoute" //Backbone 会根据顺序匹配路由
  }
 });
 // 实例化 Router
 var app_router = new AppRouter;
 app_router.on('route:getPost', function (id) {
  // 注意,参数通过这里进行传递
  alert( "Get post number " + id ); 
 });
 app_router.on('route:defaultRoute', function (actions) {
  alert( actions ); 
 });
 // 打开 Backbone 的历史记录
 Backbone.history.start();
</script>

匹配规则
Backbone 使用两种形式的变量来设置 Router 的匹配规则。第一种是 :,它可以匹配 URL 中斜杠之间的任意参数,另一种是 *,它用来匹配斜杠后面的所有部分。注意,由于第二种形式的模糊性大于第一种,所以它的匹配优先级最低。
任一形式匹配的结果会以参数的形式传递到相关的函数中,第一种规则可能返回一个或多个参数,第二种规则将整个匹配结果作为一个参数返回。
接下来,我们用实例来说明:

routes:{

 "posts/:id": "getPost",
 // <a href="http://example.com/#/posts/121">Example</a>

 "download/*path": "downloadFile",
 // <a href="http://example.com/#/download/user/images/hey.gif">Download</a>

 ":route/:action": "loadView",
 // <a href="http://example.com/#/dashboard/graph">Load Route/Action View</a>

},

app_router.on('route:getPost', function( id ){ 
 alert(id); // 匹配后,传递过来的参数为 12
});
app_router.on('route:downloadFile', function( path ){ 
 alert(path); // 匹配后,整个匹配结果作为一个参数返回,路径为 user/images/hey.gif 
});
app_router.on('route:loadView', function( route, action ){ 
 alert(route + "_" + action); // 匹配后,传递过来两个参数,此时会弹出 dashboard_graph 
});

你可能经常听说“路由器”这个词,但它常常是指一种网络设备,这种设备是网络连接、数据传输的导航和枢纽。而Backbone中的“路由器”功能与它类似,从上面的例子中你就能看出,它可以将不同的URL锚点导航到对应的Action方法。
(许多服务端Web框架中也提供了这样的机制,但Backbone.Router更侧重前端单页应用的导航。)

Backbone的路由导航是由Backbone.Router和Backbone.History两个类共同完成的:

  • Router类用于定义和解析路由规则,并将URL映射到Action。
  • History类用于监听URL的变化,和触发Action方法。

我们一般不会直接实例化一个History,因为我们在第一次创建Router实例时,会自动创建一个History的单例对象,你可以通过Backbone.history来访问这个对象。

要使用路由功能,首先我们需要定义一个Router类来声明需要监听的URL规则和Action,在刚才的例子中,我们在定义时通过routes属性来定义需要监听的URL列表,其中Key表示URL规则,Value表示当URL处于该规则时所执行的Action方法。

Hash规则
URL规则表示当前URL中的Hash(锚点)片段,我们除了能在规则中指定一般的字符串外,还需要注意两种特别的动态规则:
规则中以/(斜线)为分隔的一段字符串,在Router类内部会被转换为表达式([^\/]+),表示以/(斜线)开头的多个字符,如果在这一段规则中设置了:(冒号),则表示URL中这一段字符串将被作为参数传递给Action。
例如我们设置了规则topic/:id,当锚点为#topic/1023时,1023将被作为参数id传递给Action,规则中的参数名(:id)一般会和Action方法的形参名称相同,虽然Router并没有这样的限制,但使用相同的参数名更容易让人理解。
规则中的*(星号)会在Router内部被转换为表达式(.*?),表示零个或多个任意字符,与:(冒号)规则相比,*(星号)没有/(斜线)分隔的限制,就像我们在上面的例子中定义的*error规则一样。
Router中的*(星号)规则在被转换为正则表达式后使用非贪婪模式,因此你可以使用例如这样的组合规则:*type/:id,它能匹配#hot/1023,同时会将hot和1023作为参数传递给Action方法。

上面介绍了规则的定义方式,这些规则都会对应一个Action方法名称,该方法必须处于Router对象中。
在定义好Router类之后,我们需要实例化一个Router对象,并调用Backbone.history对象的start()方法,该方法会启动对URL的监听。在History对象内部,默认会通过onhashchange事件监听URL中Hash(锚点)的变化,对于不支持onhashchange事件的浏览器(例如IE6),History会通过setInterval心跳的方式监听。

pushState规则
Backbone.History还支持pushState方式的URL,pushState是HTML5提供的一种新特性,它能操作当前浏览器的URL(而不是仅仅改变锚点),同时不会导致页面刷新,从而使单页应用使用起来更像一套完整的流程。
要使用pushState特性,你需要先了解HTML5为该特性提供的一些方法和事件(这些方法都被定义在window.history对象中):

1.pushState():该方法可以将指定的URL添加一个新的history实体到浏览器历史里
2.replaceState():该方法可以将当前的history实体替换为指定的URL

调用pushState()和replaceState()方法,仅仅是替换当前页面的URL,而并不会真正转到这个URL地址(当使用后退或前进按钮时,也不会跳转到该URL),我们可以通过onpopstate事件来监听这两个方法引起的URL变化。

路由相关方法

1.route()方法
在设定好路由规则之后,如果需要动态调整,可以调用Router.route()方法来动态添加路由规则及Action方法,例如:

router.route('topic/:pageno/:pagesize', 'page', function(pageno, pagesize){ 
 // todo 
}); 
我们调用route()方法时,给定的规则不仅仅可以是字符串,也可以是一个正则表达式:
router.route(/^topic/(.*?)/(.*?)$/, 'page', function(pageno, pagesize){ 
 // todo 
});

2.navigate()方法
在前面的例子中,URL规则都是由我们手动输入触发的,在实际应用中,有时可能需要手动进行跳转、导航,这时可以调用

Router.navigate()方法进行控制,例如:
router.navigate('topic/1000', { 
 trigger: true 
});

这段代码将URL更改为http://localhost/index.html#topic/1000,并触发了renderDetail方法。需要注意的是,我们在第二个参数传入了trigger配置,该配置用于表示更改URL的同时是否触发相应的Action方法。

3.stop()方法
还记得我们是通过Backbone.history.start()方法来启动路由监听的,你也可以随时调用Backbone.history.stop()方法来停止监听,例如:

router.route('topic/:pageno/:pagesize', 'page', function(pageno, pagesize) { 
 Backbone.history.stop(); 
});

运行这段代码,并访问URL:http://localhost/index.html#topic/5/20,你会发现这个Action被执行之后,监听已经不再生效了。

Javascript 相关文章推荐
juqery 学习之三 选择器 简单 内容
Nov 25 Javascript
jquery文字上下滚动的实现方法
Mar 22 Javascript
JS控制文本框textarea输入字数限制的方法
Jun 17 Javascript
如何将php数组或者对象传递给javascript
Mar 20 Javascript
jQuery 2.0.3 源码分析之core(一)整体架构
May 27 Javascript
JavaScript 面向对象与原型
Apr 10 Javascript
jQuery实现图片上传和裁剪插件Croppie
Nov 29 Javascript
文本框只能输入数字的js代码(含小数点)
Jul 10 Javascript
JS获取子、父、兄节点方法小结
Aug 14 Javascript
详解使用React进行组件库开发
Feb 06 Javascript
手把手教您实现react异步加载高阶组件
Apr 07 Javascript
ES6字符串的扩展实例
Dec 21 Javascript
详解Backbone.js框架中的模型Model与其集合collection
May 05 #Javascript
基于jQuery实现动态搜索显示功能
May 05 #Javascript
jQuery插件ajaxfileupload.js实现上传文件
Oct 23 #Javascript
jQuery插件AjaxFileUpload实现ajax文件上传
May 05 #Javascript
js ajaxfileupload.js上传报错的解决方法
May 05 #Javascript
javascript执行环境及作用域详解
May 05 #Javascript
asp.net+jquery.form实现图片异步上传的方法(附jquery.form.js下载)
May 05 #Javascript
You might like
MySQL中create table语句的基本语法是
2007/01/15 PHP
PHP 进程锁定问题分析研究
2009/11/24 PHP
PHP中mb_convert_encoding与iconv函数的深入解析
2013/06/21 PHP
php实例分享之html转为rtf格式
2014/06/02 PHP
thinkphp实现附件上传功能
2017/05/26 PHP
PHP实现的简单操作SQLite数据库类与用法示例
2017/06/19 PHP
PHP实现十进制数字与二十六进制字母串相互转换操作示例
2018/08/10 PHP
javascript 事件查询综合 推荐收藏
2010/03/10 Javascript
基于Jquery的实现回车键Enter切换焦点
2010/09/14 Javascript
jquery提升性能最佳实践小结
2010/12/06 Javascript
基于jquery tab切换(防止页面刷新)
2012/05/23 Javascript
P3P Header解决Cookie跨域的问题
2013/03/12 Javascript
原始的js代码和jquery对比体会
2013/09/10 Javascript
js的2种继承方式详解
2014/03/04 Javascript
JS实现让访问者自助选择网页文字颜色的方法
2015/02/24 Javascript
前端js文件合并的三种方式推荐
2016/05/19 Javascript
基于vue.js中关于下拉框的值默认及绑定问题
2018/08/22 Javascript
Vue 样式绑定的实现方法
2019/01/15 Javascript
Angular2使用SVG自定义图表(条形图、折线图)组件示例
2019/05/10 Javascript
JavaScript WeakMap使用详解
2021/02/05 Javascript
Python使用pip安装pySerial串口通讯模块
2018/04/20 Python
python实现图片中文字分割效果
2019/07/22 Python
pd.DataFrame统计各列数值多少的实例
2019/12/05 Python
将labelme格式数据转化为标准的coco数据集格式方式
2020/02/17 Python
tensorflow使用CNN分析mnist手写体数字数据集
2020/06/17 Python
python字典按照value排序方法
2020/12/28 Python
Python实现邮件发送的详细设置方法(遇到问题)
2021/01/18 Python
微软日本官方网站:Microsoft日本
2017/11/26 全球购物
C#如何进行LDAP用户校验
2012/11/21 面试题
PyQt QMainWindow的使用示例
2021/03/24 Python
工程现场管理求职自荐信
2013/10/02 职场文书
老公给老婆的检讨书(精华篇)
2014/10/18 职场文书
2015年行风建设工作总结
2015/05/15 职场文书
致接力运动员加油稿
2015/07/21 职场文书
幼儿园小朋友毕业感言
2015/07/30 职场文书
基于docker安装zabbix的详细教程
2022/06/05 Servers