全面解析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 相关文章推荐
JavaScript中的异常捕捉介绍
Dec 31 Javascript
jQuery中removeProp()方法用法实例
Jan 05 Javascript
jQuery实现选项卡切换效果简单演示
Dec 09 Javascript
jQuery实现点击水纹波动动画
Apr 10 Javascript
JavaScript_object基础入门(必看篇)
Jun 13 Javascript
jquery实现input框获取焦点的简单实例
Jan 26 Javascript
使用jQuery实现购物车结算功能
Aug 15 jQuery
JQuery判断正整数整理小结
Aug 21 jQuery
vue-cli开发时,关于ajax跨域的解决方法(推荐)
Feb 03 Javascript
深入浅析Vue.js计算属性和侦听器
May 05 Javascript
vue+vue-router转场动画的实例代码
Sep 01 Javascript
vue组件是如何解析及渲染的?
Jan 13 Vue.js
详解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
程序员的表白神器“520”大声喊出来
2016/05/20 PHP
javascript中的new使用
2010/03/20 Javascript
仿淘宝TAB切换搜索框搜索切换的相关内容
2014/09/21 Javascript
高性能JavaScript模板引擎实现原理详解
2015/02/05 Javascript
2则自己编写的jQuery特效分享
2015/02/26 Javascript
js上传图片及预览功能实例分析
2015/04/24 Javascript
js下将金额数字每三位一逗号分隔
2016/02/19 Javascript
js自定义select下拉框美化特效
2016/05/12 Javascript
Javascript 普通函数和构造函数的区别
2016/11/05 Javascript
Angular在一个页面中使用两个ng-app的方法(二)
2017/02/20 Javascript
js读取json文件片段中的数据实例
2017/03/09 Javascript
微信小程序开发之IOS和Android兼容的问题
2017/09/26 Javascript
微信小程序实现点击按钮移动view标签的位置功能示例【附demo源码下载】
2017/12/06 Javascript
使用Vue组件实现一个简单弹窗效果
2018/04/23 Javascript
js中Generator函数的深入讲解
2019/04/07 Javascript
一次微信小程序内地图的使用实战记录
2019/09/09 Javascript
ES6 Iterator遍历器原理,应用场景及相关常用知识拓展详解
2020/02/15 Javascript
vue中echarts图表大小适应窗口大小且不需要刷新案例
2020/07/19 Javascript
如何编写一个 Webpack Loader的实现
2020/10/18 Javascript
JS中循环遍历数组的四种方式总结
2021/01/23 Javascript
Python collections模块实例讲解
2014/04/07 Python
python类继承用法实例分析
2015/05/27 Python
python实现搜索指定目录下文件及文件内搜索指定关键词的方法
2015/06/28 Python
python简单文本处理的方法
2015/07/10 Python
python3+PyQt5实现使用剪贴板做复制与粘帖示例
2017/01/24 Python
详解windows python3.7安装numpy问题的解决方法
2018/08/13 Python
浅谈pandas用groupby后对层级索引levels的处理方法
2018/11/06 Python
django项目登录中使用图片验证码的实现方法
2019/08/15 Python
浅析Django 接收所有文件,前端展示文件(包括视频,文件,图片)ajax请求
2020/03/09 Python
浅谈tensorflow 中的图片读取和裁剪方式
2020/06/30 Python
python开发一款翻译工具
2020/10/10 Python
Python实现一个论文下载器的过程
2021/01/18 Python
美国50岁以上单身人士约会平台:SilverSingles
2018/06/29 全球购物
经典公益广告词
2014/03/13 职场文书
2014年学生会主席工作总结
2014/11/07 职场文书
写给孩子的新学期寄语
2015/02/27 职场文书