×

EmberJS 教程

EmberJS 概述EmberJS 环境配置EmberJS 应用EmberJS 对象模型EmberJS 模板EmberJS 路由器EmberJS 组件EmberJS 模型EmberJS 视图EmberJS 控制器EmberJS 测试EmberJS 指定查询参数

Ember 对象模型

Ember 类的定义 初始化 继承Ember 类的扩展Ember 计算属性Ember 观察者Ember 数据绑定Ember 枚举Ember 第一章对象模型小结

Ember handlebars模板

Ember handlebars基础Ember handlebars条件表达式Ember handlebars遍历标签Ember handlebars显示对象键Ember handlebars属性绑定Ember {{link-to}} 助手Ember 路由 模板执行渲染顺序Ember {{action}} 助手Ember 表单元素Ember 调试助手Ember 工具类的助手Ember 第二章模板小结

Ember 路由

Ember 路由定义Ember 指定与路由关联的模型Ember 模板渲染Ember 路由重定向Ember 路由终止挑战和激活Ember loading error子路由Ember 查询参数Ember 异步路由

Ember 组件

Ember 组件定义Ember 属性传递Ember 包裹内容自定义包裹组件的HTML标签Ember 处理事件Ember action触发变化

Ember 控制器

Ember 控制器Ember 管理控制器的依赖关系

Ember 模型

Ember model简介Ember 定义模型Ember 记录查询Ember 新建、更新、删除记录Ember 设置记录到StoreEmber model的关联关系处理Ember 元数据Ember 自定义适配器Ember 自定义序列号器

Ember 测试

Ember 测试简介Ember 验收测试Ember 单元测试

Ember 路由、模板的执行、渲染顺序


在Ember中路由和模板的执行都是有一定顺序的,它们的顺序为:主路由->子路由1->子路由2->子路由3->……。模板渲染的顺序与路由执行顺序刚好相反,从最后一个模板开始解析渲染。

注意:模板的渲染是在所有路由执行完之后,从最后一个模板开始。关于这一点下面的代码会演示验证,官网教程有介绍,点击查看。

比如有一路由格式为application/posts/detail/comments/comment,此时路由执行的顺序为:application/posts -> detail -> comments -> commentapplication是项目默认的路由,用户自定义的所有路由都是application的子路由(默认情况下),相对应的模板也是这样,所有用户自定义的模板都是application.hbs的子模板。如果你要修改模板的渲染层次你可以在route中重写renderTemplate回调函数,在函数内使用render方法指定要渲染的模板(如:render('other'),渲染到other这个模板上)更多有关信息请查看这里。并且它们对应的文件模板结构如下图:

文件模板结构

路由与模板是相对应的,所以模板的目录结构与路由的目录结构是一致的。 你有两种方式构建上述目录:

  1. 手动创建
  2. 使用命令,比如创建comment.js使用命令:ember generate route posts/detail/comments/commentEmber CLI会自动为我们创建目录和文件。

创建好目录结构之后我们添加一些代码到每个文件。运行项目之后你就会一目了然了……。 下面我按前面讲的路由执行顺序分别列出每个文件的内容。

//  app/routes/posts.js

import Ember from 'ember';

export default Ember.Route.extend({
    model: function() { 
        console.log('running in posts...');
        return { id: 1, routeName: 'The route is posts'};
        // return Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');
    }

});
import Ember from 'ember';

export default Ember.Route.extend({

    model: function(params) {
        console.log('params id = ' + params.post_id);
        console.log('running in detail....');

        return { id: 1, routeName: 'The route is detail..' };
    }
}); 
//  app/routes/posts/detail.js

import Ember from 'ember';

export default Ember.Route.extend({

    model: function(params) {
        console.log('params id = ' + params.post_id);
        console.log('running in detail....');

        return { id: 1, routeName: 'The route is detail..' };
    }
}); 
//  app/routes/posts/detail/comments.js

import Ember from 'ember';

export default Ember.Route.extend({
    model: function() {
        console.log('running in comments...');
        return { id: 1, routName: 'The route is comments....'};
    }
});
//  app/routes/posts/detail/comments/comment.js

import Ember from 'ember';

export default Ember.Route.extend({
    model: function(params) {
        console.log('params id = ' + params.post_id);
        console.log('running in comment...');
        return { id: 1, routeName: 'The route is comment...'};
    }
});

下面是模板各个文件的内容。其列出才顺序与路由的顺序一致。


{{model.routeName}} >> {{outlet}}

{{model.routeName}} >> {{outlet}}

{{model.routeName}} >> {{outlet}}

{{model.routeName}} >> {{outlet}}

下图是路由执行的顺序,并且在执行的过程中渲染路由对应的模板。

路由执行的顺序

从上图中可用清楚的看到当你运行一个URL时,与URL相关的路由是怎么执行的。

  1. 执行主路由(默认是application),此时进入到路由的model回调方法,并且返回了一个对象{ id: 1, routeName: 'The route is application...' },执行完回调之后继续转到子路由执行直到最后一个路由执行完毕,所有的路由执行完毕之后开始渲染页面。
  2. 页面的渲染则是从最后一个路由对应的模板开始,并沿着最近的父模板往回渲染。 为了验证是否是这样的执行顺序,下面修改detail.jscomments.js。在代码中加入一个模拟休眠的操作。
    
    //  app/routes/posts/detail.js

import Ember from 'ember';

export default Ember.Route.extend({

model: function(params) {
    console.log('params id = ' + params.post_id);
    console.log('running in detail....');

    //  执行一个循环,模拟休眠
    for (var i = 0; i < 10000000000; i++) {

    }
    console.log('The comment route executed...');

    return { id: 1, routeName: 'The route is detail..' };
}

});

```javascript
//  app/routes/posts/detail/comments.js

import Ember from 'ember';

export default Ember.Route.extend({
    model: function(params) {
        console.log('params id = ' + params.post_id);
        console.log('running in comment...'); 
        //  执行一个循环,模拟休眠
        for (var i = 0; i < 10000000000; i++) {

        }

        return { id: 1, routeName: 'The route is comment...'};
    }
});

刷新页面,注意查看控制台输出信息和页面显示的内容。 新开一个窗口,执行URL:http://localhost:4200/posts/2/comments

run result

控制台输出到这里时处理等待(执行for循环),此时已经执行了两个路由applicationposts,并且正在执行detail,但是页面是空白的,没有任何HTML元素。

run result

detail路由执行完成之后转到路由comments。然后执行到for循环模拟休眠,此时页面仍然是没有任何HTML元素。然后等到所有route执行完毕之后,界面才显示model回调里设置的信息。

run result

每个子路由设置的信息都会渲染到最近一个父路由对应模板的{{outlet}}上面。

run result

  1. 渲染comment 得到的内如为:“comment渲染完成”
  2. 渲染comment最近的父模板comments 得到的内容为:“comment渲染完成 comments渲染完成”
  3. 渲染comments最近的父模板detail 得到的内容为:“comment渲染完成 comments渲染完成 detail渲染完成”
  4. 渲染detail最近的父模板posts 得到的内容为:“comment渲染完成 comments渲染完成 detail渲染完成 posts渲染完成”
  5. 渲染posts最近的父模板application 得到的内容为:“comment渲染完成 comments渲染完成 detail渲染完成 posts渲染完成 application渲染完成”

只要记住一句话:子模板的都会渲染到父模板的{{outlet}}上,最终所有的模板都会被渲染到application{{outlet}}上。


博文完整代码放在Github(博文经过多次修改,博文上的代码与github代码可能又出入,不过影响不大!),如果你觉得博文对你有点用,请在github项目上给我点个star吧。您的肯定对我来说是最大的动力!!


分类导航

关注微信下载离线手册

bootwiki移动版 bootwiki
(群号:472910771)