简介

Ember Route,路由管理,在ember中具有很重要的意义,他负责管理整个路由的规则,什么时候应该渲染什么模板等,总体来说,他的功能有

  • 渲染一个模板
  • 加载model以供模板使用
  • 重定向到一个新的路由,比如说权限控制情况下,一个人不允许访问某一个页面
  • 可以负责处理一个action(动作或者事件)

基本配置

创建route

使用命令行创建ember g route <your-route-name>
执行命令后,会在app/templates目录下生成模板,会在app/routes目录下生成js文件,同时修改app/route.js文件。

这里主要说明一下route.js文件,其基本格式为:

Router.map(function() {this.route('path1');this.route('favorites', { path: '/path2' });
});

当访问/path1的时候,渲染path1模板,当访问/path2的时候,渲染favorites模板。
如果是嵌套的路由(子路由),比如path1/path2,那么形式可能是这样的, 创建的时候只需要ember g route path1/path2

Router.map(function() {this.route('path1',function(){this.route('path2');});
});

如果想要设置初始页面,可以这样,这样就可以为/设置一个初始的路由:

Router.map(function() {this.route('index',{path:'/'});
});

如果url中具有动态的参数呢?例如localhost:8000/path1/path2/2,这个2可能是一个id,又或者localhost:8000/path1/path2/2/edit这可能代表一个id为2的数据的编辑页面,那么在route.js可以如下表示:

Router.map(function() {this.route('path1', function(){this.route('path2',{path:'/path2/:id'});});
});

通过这种方式,就可以进行访问,但是注意,以上的形式下localhost:8000/path1/path2是无法访问的。
在这种情况下,如何使用这个id参数呢?

//app/routes/path1/path2
export default Ember.Route.extend({model(params){let id = params.id;return this.store.findRecord('model-example',id).then((data)=>{return data});}
});

如上就可以对参数进行使用。理论上来讲,是不能够修改url中的参数的,所以手动赋值是无效的,也无法进行刷新等动作。同时需要注意,不要给参数起一样的名字,那样就会不起作用,下面的李自力有2个id,所以不会起作用:

Router.map(function() {this.route('photo', { path: '/photo/:id' }, function() {this.route('comment', { path: '/comment/:id' });});
});

路由、模板的渲染规则

所有的路由都有一个根的父路由:application,也就是说,我们创建的所有路由,都是经由application渲染的。
我们我们查看模板文件,会发现路由的模板的内容都是{{outlet}}。每一个模板都会渲染到父模板的{{outlet}}上。一层一层的往上渲染。
比如经典的圣杯模型,在我们看来,可能上边栏侧边栏和下边栏是不变的,那么我们可以定义我们的application.hbs为:

<div class="header">这是上边栏</div>
<div class="sider">这是侧边栏</div>
<div class="content">
{{outlet}}
</div>
<div class="footer">这是下边栏</div>

那么渲染的时候,只会渲染到content中。
接下来我们讲解一下渲染的规则。这里这篇文章介绍的非常好Ember.js 入门指南之十四番外篇,路由、模板的执行、渲染顺序

渲染其他的模板也是允许的

一般情况下,我们要渲染的模板都是自己的哪一个,但是,ember也允许你渲染其他的模板,例如正常情况下,不做任何操作,path1/path2渲染的模板就是app/templates/path1/path2.hbs, 但是如果你想要进行更换,只需要重载方法renderTemplate()

//app/routes/path1/path2.js
export default Ember.Route.extend({renderTemplate() {this.render('path1/path2', {into: 'templateName',outlet: 'anOutletName'});//this.render('path3');//这个语句可以使用path3替换path1/path2}
});

上面这个方法可以将path1/path2渲染到templateName 中使用{{outlet 'anOutletName'}}的地方。详情请见render。

model的执行顺序

model的执行顺序为从主到子。例如urlpath1/path2,那么model的执行顺序为application->path1->path2

模板的渲染顺序

首先,注意一点,就是,如果model执行完成后,才开始进行模板的渲染。
模板渲染的顺序为从子到主,也就是path2->path1->application->path1。渲染完成后,展示。这里需要全部渲染完后展示。

路由的重定向

路由重定向,例如,当权限控制等的时候,跳转到一个异常页面等,常常会用到,常用方法为transitionTo()transitionTo()的表现和helperlink-to的表现一致。另外还有一个方法replaceWith(),使用起来差不多。

transitionTo()可以在各个阶段使用:

//app/routes/path1.js
export default Ember.Route.extend({//在model初始化之前(发送请求之前)beforeModel(){this.transitionTo('/path2');},//在初始化的时候,model(){return this.findRecord('model-example',1).then((data)=>{if(!data){this.transitionTo('/path2');}else{return data;}});}//在model初始化之后afterModel(){let model = this.modelFor('path1');if(model.length){this.transitionTo('/path2');}},actions:{//可以在action中,比如点击后transitionToPath2(){this.transitionTo('/path2');}}
});

如果是要重定向到子路由,也可以直接在beforeModel() afterModel() model()中进行,但是如果这样的,考虑到子路由的执行过程,会再次将父路由执行一次,所有,ember有一个更加优化的方式redirect

//app/routes/path1.js
redirect(model, transition) {  this.transitionTo('path1.path2');
}

还有一些高级的用法,比如复杂url或者带参数的情况,注意这种情况下不能使用replaceWith进行替换:

//路由为 this.route('path2',{path:path2/:id});
this.transitionTo('/path2/2');
this.transitionTo('/path2',2);//同上
{{link-to 'path2' 2}}//路由为 this.route('path2',{path:path2/:id}, function(){this.route('path3',{path:'path3/:p_id'})});
this.transitionTo('/path2/2/paht3/3');
{{link-to 'path2' 2 3}}//路由为this.route('path2',{path:path2/:id}); 且有参数`queryParams`(这个概念会在controller中说)
this.transitionTo('/path2/2?params=1');
this.transitionTo('/path2/2',{queryParams: { params: '1' }});//同上
{{link-to 'path2' 2 (query-params params='1')}}

终止与重试路由跳转

有一些情况下,我们可能需要手动终止路由的跳转,或者是终止之后再重试。

当用户通过{{link-to}}、transition方法或者直接执行URL来转换路由,当前路由会自动执行willTransition方法。每个活动的路由都可以决定是否执行转换路由。
如果你正在填写一个表单,然后,无意点击了跳转,这样你的填写的数据就都丢失了,很不友好。所以一般会有一个确认页面。所以我们可以通过willTransition来先让用户确认是否离开再说。

//  app/routes/path1.js
import Ember from 'ember';
export default Ember.Route.extend({  actions: {willTransition: function(transition) {if (!confirm("你确定要离开这个页面吗?")) {transition.abort();} else {return true;}}}
});

load 以及 error的处理

我们假设有这样的一个model:slow-model,这个model返回结果非常的慢,那么我们的以routedemo1/case1为例,如果route中加载情况如下:

model(){return this.store.findAll('slow-model').then((data)=>{return data;});
}

那么,在slow-model返回结果之前,页面会一直是空白,这个非常不美观,我们一般会采用一个loading的图标或者有一个提示等。

Ember提供的解决办法是:在beforeModel、model、afterModel回调还没返回前先进入一个叫loading的子状态,然后渲染一个叫<your-route-name>-loading的模板(如果是application路由则对应的直接是loading、error不需要前缀)。

同样以demo1/path1为例:

//app/templates/application.hbs
<p>application</p>
<p>application</p>
<p>application</p>
{{outlet}}
//app/routes/demo1.js
import Ember from 'ember';
export default Ember.Route.extend({model() {return this.store.findAll('slow-model');}
})
//app/templates/demo1.hbs
<p>demo1</p>
<p>demo1</p>
<p>demo1</p>
{{outlet}}
//app/templates/demo1-loading.hbs
<p>demo1-loading</p>
<p>demo1-loading</p>
<p>demo1-loading</p>
//app/routes/demo1/case1.js
import Ember from 'ember';
export default Ember.Route.extend({model() {return this.store.findAll('slow-model');}
//app/templates/demo1/case1.hbs
<p>case1</p>
<p>case1</p>
<p>case1</p>
//app/templates/demo1/case1-loading.hbs
<p>case1-loading</p>
<p>case1-loading</p>
<p>case1-loading</p>

以上的代码,假设slow-model是非常慢的,那么页面的展示顺序为:



demo1/case1为例,结合我们说过的路由渲染顺序为,注意,渲染顺序还是从子到父的:
- demo1.case1-loading
- demo1-loading
- loading(application的loading)

从上图可以看出,在model没有加载好的时候,会先用<your-route-name>-loading来对本来的模板进行替换。那么在这个过程中,model的执行顺序呢?这个过程中,model为先执行父route的model,也就是demo1的model,当请求发出,直到下一个子路由的mode请求发出,一直都是loading状态,也就是:

然后子路由请求发出,也就是demo1/case1请求发出后,进入子路由的loading状态:

数据返回后,结束:

另外,在beforeModel、model、afterModel回调没有立即返回之前,会先执行一个名为loading的事件。

    actions: {loading: function(transition, originRoute) {alert("Sorry this is taking so long to load!!");}}

loading事件实在model回调返回之前执行。这里需要注意一下,如果同时定义了loading回调,以及<your-route-name>-loading子模板,那么会只执行loading回调,而不会渲染模板。

error的情况也类似,不过过程是在model返回且失败的情况下,而loading为未返回的情况下:
demo1/case1为例,结合我们说过的路由渲染顺序为,注意,渲染顺序还是从子到父的(考虑到model的执行顺序,不会出现父吧子覆盖的情况,因为执行不到- -):
- demo1.case1-error
- demo1-error
- error(application的error)

error的回调为:

actions: {error(error, transition) {if (error.status === '403') {this.replaceWith('login');} else {// Let the route above this handle the error.return true;}}}

查询参数

动态路由的情况,我们已经说过,但是,如果是带参数呢?举例,我们常用的分页操作,一般都会带上pageSize=10&pageNum=2意味着第二页取10个,这样,那么在请求中怎么做呢?
这里就要使用到controller的概念,对于路由demo1/case1而言,如果要增加参数,那么就需要创建相应的controller。创建controller:ember g controller demo1/case1,以分页为例:

//app/controllers/demo1/case1.js
import Ember from 'ember';
export default Ember.Controller.extend({queryParams: ['pageSize','pageNum'],pageSize: null,pageNum:null
});

这样就会在请求上带上这个参数,如果你没带的话,还是会取到这个参数,只不过都是null罢了。你可以为他们设置默认值:

//app/controllers/demo1/case1.js
import Ember from 'ember';
export default Ember.Controller.extend({queryParams: ['pageSize','pageNum'],pageSize: 10,pageNum:1
});

那么默认就是第一页的10个。注意,如果你传的值就是和默认的一样,在请求上是不会展示的!

关于查询参数的用法,跳转,在之前的transitionTo()方法以及link-to助手的的时候已经说过。

controller中还可以调用model的数据,以及使用计算属性,官网上给出一个例子:

import Ember from 'ember';export default Ember.Controller.extend({queryParams: ['category'],category: null,filteredArticles: Ember.computed('category', 'model', function() {var category = this.get('category');var articles = this.get('model');if (category) {return articles.filterBy('category', category);} else {return articles;}})
});

这样,filteredArticles的值就会一直随着model的改变而改变,而filteredArticles的值是可以直接在模板中使用的,所以说间接的导致模板元素的变化。

关于查询参数,还有一个点很重要,就是更新数据。因为毕竟url改变了,如果数据却没有更新的话,简直不合理。

上述的做法相当于这样:

this.transitionTo({ queryParams: { pageNum: 3 }});
{{link-to (query-param pageNum=3)}}

注意,这种方式,由于没有修改路由的结构,只不过是修改了参数,所以只能说是不完整的路由切换,这种不完整,也就意味着比如model和setupController回调方法就不会被执行,只是使得controller里的属性值为新的查询参数值以及更新URL。(当然,如果是跳转到一个新的路由,还是会改变的)。

如果单纯的按照上面的写法,model是不会更新的。那么如何更新model中的数据呢?这需要你在对应的路由中配置一个名为queryParams哈希对象。并且需要设置一个名为refreshModel的查询参数,这个参数的值为true。

import Ember from 'ember';export default Ember.Route.extend({queryParams: {category: {refreshModel: true}},model(params) {// This gets called upon entering 'articles' route// for the first time, and we opt into refiring it upon// query param changes by setting `refreshModel:true` above.// params has format of { category: "someValueOrJustNull" },// which we can forward to the server.return this.get('store').query('article', params);}
});

那么每次你修改参数后,都会更新model并且执行setupController。但是要注意,这个也会同时刷新父路由!

那么如果要手动触发呢?比如搜索条件,你想要点击搜索的时候才更新数据,或者说只更新自己的路由的信息,怎么办呢?那么可以这么做

import Ember from 'ember';export default Ember.Route.extend({model(){console.log('model');},setupCotroller(controller,model){console.log('setupcontroller');},actions:{//如果只需要更新modelclickAction(){this.refresh();},//同时更新model以及setupcontrollerclickAction1(){let self = this, controller=this.get('controller');this.model().then((data)=>{controller.set('model', data);self.setupController(controller,data); })}}
});

注意上面的方法都只能更新自己的model,如果想要更新父model呢?参考如下:

import Ember from 'ember';export default Ember.Route.extend({model(){console.log('model');},setupCotroller(controller,model){console.log('setupcontroller');},actions:{//更新父modelclickAction(){//this.refresh();//这个只能更新自己的modelthis.modelFor('parent').reload();//指定父model然后reload可以实现更新}}
});

异步路由

//TODO

Ember Route相关推荐

  1. Ember.js 入门指南——查询记录

    2019独角兽企业重金招聘Python工程师标准>>> store提供了统一的获取数据的接口.包括创建新记录.修改记录.删除记录等,更多有关Store API请看这个网址的介绍:ht ...

  2. Ember.js如何与后端服务交互?adapter、store、ember data关系揭秘

    2019独角兽企业重金招聘Python工程师标准>>> 文章来源:Ember Teach 本项目讲解如何使用adapter.EmberData以及怎么连接到本地数据库. 项目简介 主 ...

  3. Ember.js 入门指南——handlebars属性绑定

    2019独角兽企业重金招聘Python工程师标准>>> 本文从http://www.ibeginer.sinaapp.com迁移过来,欢迎访问原页面. 简单讲属性绑定其实就是在HTM ...

  4. Day 24: 使用Yeoman自动构建Ember项目

    到目前为止,我们这个系列讨论了Bower.AngularJS.GruntJS.PhoneGap.Meteor.Ember和TimelineJS等JavaScript技术.今天的<30天学习30种 ...

  5. Ember.js 入门指南——路由切换的终止和回跳

    2019独角兽企业重金招聘Python工程师标准>>> 在路由的切换过程中,Ember路由器会通过回调(beforeModel.model.afterModel.redirect)解 ...

  6. Ember.js 入门指南——番外篇,路由、模板的执行、渲染顺序

    2019独角兽企业重金招聘Python工程师标准>>> 在Ember中路由和模板的执行都是有一定顺序的,它们的顺序为:主路由à子路由1à子路由2à子路由3à--.模板渲染的顺序与路由 ...

  7. Ember.js如何与后端服务交互?adapter、store、ember data关系揭秘 1

    文章来源:Ember Teach 本项目讲解如何使用adapter.EmberData以及怎么连接到本地数据库. 项目简介 主要内容 适配器使用 如何持久化数据到本地数据库 简单的后端服务 最近经常有 ...

  8. ember js搭建web_使用Ember.js构建雄心勃勃的Web应用程序

    ember js搭建web Ember.js is a solid single page application framework for building modern web applicat ...

  9. 使用service实现登录、权限控制

    2019独角兽企业重金招聘Python工程师标准>>> 文章来源:http://blog.ddlisting.com 官网对于登录.用户权限的介绍只有一段简单的说明,并没有详细说明如 ...

  10. Day 19: EmberJS 入门指南

    到目前为止,我们这一系列文章涉及了Bower.AngularJS.GruntJS.PhoneGap和MeteorJS 这些JavaScript技术.今天我打算学习一个名为Ember的框架.本文将介绍如 ...

最新文章

  1. Python图像拼接:创建全景图
  2. memcache缓存失效
  3. audio 上一首 下一首 自定义样式_我们的歌:盛典即将来临,勤深深还有一首歌,这场表演值得期待...
  4. java菜单栏的功能怎么被关闭_【求助帖】 菜单栏的监听问题
  5. Pytorch搭建yolo3目标检测平台
  6. 现代支付行号查询系统_旅游景区智能管理系统-景区智能导航软件
  7. 个人管理 - 程序员的四个阶段
  8. 傅里叶分析(matlab)
  9. spring期刊状态_无状态Spring安全性第2部分:无状态认证
  10. 数据结构链表之循环链表——4
  11. crontab shell 每5秒执行_视频 |全球最快全自动播种分拣机器人,每5秒处理一件货物...
  12. 如何与Ansible共同托管GitHub和GitLab
  13. hadoop ha环境下的datanode启动报错java.lang.NumberFormatException: For input string: 10m
  14. 基于PCQQ协议的Python QQ机器人库
  15. 全国24小时降水量pyecharts可视化分析
  16. Springboot奶茶店点餐系统vtj89计算机毕业设计-课程设计-期末作业-毕设程序代做
  17. html图片转换特效,css3图片切换效果
  18. www-authenticate
  19. 数据库、mysql和sql的入门简明教程
  20. 数据分析之Numpy创建二维空数组

热门文章

  1. 学习使用NMF非负矩阵分解算法
  2. html 苹果微信录音js,基于JS开发微信网页录音功能的实例代码
  3. 【有关数据库的问题】运行时错误‘3706’:未找到提供程序。该程序可能未正确安装。
  4. 传感器检测技术——概论
  5. word参考文献格式设置(国标下载)
  6. pythonlinux安装 pandas_linux pandas安装
  7. 101—200之间的素数-Java编写
  8. micropython(esp8266)SG90舵机控制
  9. UE4 蓝图实现AI随机移动
  10. 松下服务器显示18号报警,松下伺服报警代码预览表