【JavsScript】Ember.js

现在,我们经常都可以看到复杂的JavaScript应用程序,由于这些应用程序变得越来越复杂,一长串的jQuery回调语句或者通过应用程序在各个状态执行不同的函数调用,这些做法都会变得无法再让人接受,这导致了JavaScript开发人员开始寻找一种组织和效率更优秀的开发方式。

实现组织和效率的其中一个最常用的架构模式,就是我们熟知的Model View Controller (MVC)模式,这种模式鼓励开发人员将其应用程序的不同部分分割为更易于管理的模块,我们不必使用一个函数直接调用数据库,通过创建了一个Model(模型或实体)来管理数据库;通过模板(Template)或视图(View)来简化显示代码; 最后,通过使用控制器(Controller)来处理我们的应用程序的请求,MVC模式尽量降低每个模块之间的耦合度,提供程序的开发效率。

我们熟知的Javascript MVC框架有:Ember.js、Backbone.js、Knockout.js、Spine.js、Batman.js 和 Angular.js等。

图1 Javascript MVC framework

通过上图,我们我们可以清楚地了解Javascript MVC框架之间的特性,复杂度和学习曲线的区别,从左到右我们了解到各个Javascript MVC框架是否支持数据绑定(Data Binding)、模板(Templating)和持久化等特性,从下到上MVC框架的复杂性递增,说实话我并没有去对比每个框架之间的优劣,如果大家有做过相关的对比或看过有关的文章也不吝赐教。

在接下来的博文中,我们将介绍Ember.js的使用。

目录

1.1.2 正文

Ember.js是一个JavaScript的MVC框架,它由Apple前雇员创建的SproutCore 2.0改名进化而来,Ember已经发布到1.0.0-RC.3

MVC定义

在介绍Ember之前,首先让我们回顾一下MVC模式,下面我们讲通过一个例子介绍MVC模式在程序设计中的作用,例如:

1. 用户执行一个操作,比如敲击键盘或单击鼠标按钮。

2. 控制器(Controller)接收输入并触发一个消息给模型(Model)。

3. 模型根据消息修改其内容(CRUD操作)。

4. 视图(View)监视模型中的变更,并将相应地更新呈现到用户界面中。

通过上面,我们了解到MVC中各个部件之间的作用和联系,在了解 MVC 模式的工作方式后,我们可以更加明确是否需要在我们的项目中引入Javascript的MVC框架。

在构建Ember应用程序时,我们会使用到六个主要部件:应用程序(Application)、模型(Model)、视图(View)、模板(Template)、路由(Routing)和控制器(Controller)。

接下来,我们将通过实现一个具体的程序来介绍Ember的使用。

设置Ember

首先,我们需要引用一系列Javascript库,所以我们在程序中添加js文件,并且把以下js文件保存到该文件夹中:

ember.js: ember 1.0.0-rc.3

ember-data.js: revision 12

handlebars.js: handlebars 1.2.rc.3

jquery.js: jQuery 1.9.1

app.js: 我们的应用程代码

上面,我们把一系列的js文件保存到了本地中,当然我们也可以通过使用CDN(内容分发网络)来获取相应Javascript库,接下来,让我们创建index.html页面。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="description" content="" />
    <meta name="description" content="" />
    <meta name="keywords" content="" />
    <meta name="author" content="" />
    <title></title>
    <link rel="stylesheet" href="" type="text/css" />
    <link rel="stylesheet" href="" type="text/css" />
</head>
<body>
    <!-- Add Javascript libs Reference -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="js/libs/handlebars-1.0.0-rc.3.js"></script>
    <script src="js/libs/ember-1.0.0-rc.2.js"></script>
    <script src="js/libs/ember-data.js"></script>
    <script src="js/app.js"></script>
</body>
</html>

现在,我们已经实现了第一个Ember程序,但是它还没有具体功能,接下来,我们将给程序添加功能。

模板(Handlebars)

Ember.js使用的是Handlebars模板引擎,在我们开始使用之前,首先让我们先简单介绍一下handlebars.js;如果大家有使用过jQuery模板或其他脚本模板,那么对于掌握handlebars.js的使用就没有太大的困难了,如果确实没有使用过也不用担心,因为handlebars.js的使用也是挺简单的。

它让开发人员可以混合原始HTML和Handlebars表达式生成渲染相应的HTML;表达式以包括在{{}}中,我们可以通过两种方法把Handlebars模板加载到页面中,我们可以直接内嵌的html页面中,通过在页面中添加类型为text/x-handlebars的脚本标记内;或保存到以handlebars或hbs为后缀的文件中,然后通过Ember.js加载到页面中。

为了简单起见,我们把Handlebars脚本直接嵌入到index.html页面中。

<script type="text/x-handlebars" data-template-name="application">
        <h1>Employee System</h1>
        {{outlet}}
</script>

上面,我们定义了模板application,并且添加了Handlebars表达式{{outlet}},它的作用就类似一个占位符,告诉Ember这里的内容要动态地加载到页面当中,当我们在浏览器中打开index页面并没有显示模板中的信息。

应用程序(Application)

这是由于我们还没有定义Ember程序,每个Ember应用程序都需要一个Ember应用程序实例,接下来让我们在app.js中创建第一个Ember应用程序实例吧!

首先,我们创建一个Ember应用程序实例,具体实现如下:

// Creates an application instance.
App = Ember.Application.create();

上面,我们定义了一个名为 App 的Ember应用程序,当然我们可以把程序命名为任意的,但有一点我们要注意的是Ember要求变量的名称都以大写字母开头。

现在,我们在浏览器中打开页面,可以显示模板加载的信息了。

图2 Index页面

也许有人会问Ember怎么知道哪些模板需要加载呢?更重要的一点是,我们并没有告诉Ember要加载的模板名称,我们只是直接把模板application嵌入到页面中。

其实,这里有个“潜规则”:如果我们没有定义ApplicationView(应用程序视图),那么Ember会自动生成一个ApplicationView并且默认加载名为application的模板,假设,我们把模板重命名为application1,那么默认的ApplicationView将找不到要加载的模板。

当然,我们也可以通过定义ApplicationView来指定需要加载的模板名称,具体实现如

// Defines an application view, then loading
// relative templates.
App.ApplicationView = Ember.View.extend({
  templateName: ‘application1‘
});

现在,我们还有一个疑问就是表达式{{outlet}}中的内容该如何加载显示呢?

路由(Routing)

由于{{outlet}}的内容是根据路由选择后动态获取的模板内容,所以我们先介绍Ember程序的路由,它可以帮助管理应该程序的状态和用户导航所需资源的资源;当我们的应用程序启动时,路由是负责显示模板,加载数据,以及管理应用程序的状态。

现在,我们通过指定URL方式义来定义应用程序的路由,具体定义如下:

// Defines a goal routing home and
// the detail information of employee routing.
App.Router.map(function() {
    this.route("home", {path: "/"});
    this.route("employee", {path: "/employee/:employee_id"});
});

上面,我们定义了两个路由分别是:应用程序的全局路由home和employee,在index页面进行加载同时访问home路由的模板,数据和应用程序状态;而employee路由将根据employee_id访问每个一个员工的基本信息。

接下来,我们定义home模板,具体实现如下:

<script type="text/x-handlebars" data-template-name="home">
        <h3>Employee Information</h3>
        <ul>
        {{#each item in employeeInfo}}
        <li>item</li>
        {{each}}
        </ul>
</script>

上面,我们定义了home模板,并且使用了each表达来迭代访问employeeInfo对象中的元素,这时我们又有一个疑问了,那就是employeeInfo对象从哪里获取呢?

前面,我们提到Controller负责从Model中获取数据,然后通过模板加载显示,那么我们可以通过显市定义Controller来获取数据,如果我们不定义的话,Ember会自动生成一个HomeController。

// Defines a custom controll.
 App.HomeController = Ember.Controller.extend({
      employeeInfo: [‘Jackson Huang‘, ‘Ada Li‘, ‘JK Rush‘]
 });

上面,我们自定义了HomeController并且初始化了employeeInfo数组,现在我们刷新一下index页面。

图3 Index页面

现在,我们又有一个疑问了,假如,我们程序有很多资源要访问,那么我们是否都显式地定义Controller呢?

其实,我们还可以通过定义路由控制器实现自动选择控制器,而且Ember会自动生成相应的Controller无需我们编写任何代码,具体实现如下:

  // Defines a routing handler.
  App.HomeRoute = Ember.Route.extend({
    model: function(){
     return [‘Jackson Huang‘, ‘Ada Li‘, ‘JK Rush‘];
   },
   setupController: function(controller, model){
    controller.set(‘content‘, model)
  }
});

现在,我们定义了路由控制器App.HomeRoute并且重写了方法setupController,它接收路由处理程序匹配的控制器作为第一个参数即HomeController,接着我们给HomeController传递model参数,那么HomeController就可以获取相应的数据并且加载到模板中显示了。

上面,我们成功把数据加载到页面中,但是数据都是直接hardcode在Controller中,我们并没有定义Model来获取数据。

接下来,我们将实现从Fixtures中获取数据,这时我们需要使用ember-data.js库,具体实现如下。

// Customs a store.
App.Store = DS.Store.extend({
  // Notify the version of ember data api used.
  revision: 12,

  // Used FixtureAdapter.
  adapter: ‘DS.FixtureAdapter‘
});

上面,我们在app.js中定义DS.Store的子类App.Store,并且申明我们程序使用Ember data api的版本是12,当api版本更新或使用的版本太旧时,ember-data.js就会返回相应的错误信息。

例如:当前的ember-data.js版本是12,如果我们在app.js中定义使用的是版本1的api,在控制台中我们就会看到以下的错误信息。

图4 ember-data.js版本信息

模型(Model)

模型是一个用来表示应用程序数据的对象,它可能是一个简单的数组或通过RESTful API动态检索的数据;ember-data.js提供加载、映射和更新应用程序模型的API。

ember-data.js为每个应用程序都提供存储空间,存储空间负责保持已加载的Model和检索还未加载的Model。

前面,我们定义了应用程序App,现在,需要给程序提供数据也就是员工信息,所以我们要创建程序的模型(实体)Employee,接下来我们将实现模型的定义。

// Defines a employee model.
App.Employee = DS.Model.extend({
  name: DS.attr(‘string‘),
  department: DS.attr(‘string‘),
  title: DS.attr(‘string‘)
})

上面,我们定义了Employee模型,它继承了DS.Model并且包含三个字段分别是name,department和title。

接下来,我们通过定义App.Employee.FIXTURES,模拟从服务器端获取数据。

// Defines a JSON array.
App.Employee.FIXTURES = [
{
  id: 1,
  name: ‘Jackson Huang‘,
  department: ‘IT‘,
  title: ‘programmer‘
},
{
  id: 2,
  name: ‘Ada Chen‘,
  department: ‘purchasing‘,
  title: ‘buyer‘
},
{
  id: 3,
  name: ‘JK Rush‘,
  department: ‘IT‘,
  title: ‘programmer‘
},
{
  id: 4,
  name: ‘Lucy Liu‘,
  department: ‘IT‘,
  title: ‘tester‘
},
{
  id: 5,
  name: ‘Julia Liu‘,
  department: ‘HR‘,
  title: ‘Manager‘
}
];

上面,我们定义了JSON数组App.Employee.FIXTURES,它包含了一系列员工的基本信息。

接下来,我们修改home和添加employee模板,具体实现如下:

<!-- Home temp START -->
<script type="text/x-handlebars" data-template-name="home">
        <h3>
            Employee Information</h3>
        <ul>
            {{#each item in content}}
            <li>{{item}}</li>
            {{/each}}
        </ul>
        <h3>
            Employee</h3>
        <ul>
            {{#each employee in employees}} {{#linkTo "employee" employee}}
            <p>
                {{employee.name}}
            </p>
            {{/linkTo}} {{/each}}
        </ul>
</script>
<!-- Home temp END -->

<!-- Employee temp START -->
<script type="text/x-handlebars" data-template-name="employee">
        <div>
            <h3>
                Name: {{name}}</h3>
            <p>
                Department: {{department}}
            </p>
            <p>
                Title: {{title}}
            </p>
            {{#linkTo home class=‘btn btn-primary‘}}Back{{/linkTo}}
        </div>
</script>
<!-- Employee temp END -->

在home模板中,我们添加each表达式迭代访问employee元素,然后通过linkTo选择employee路由;然后根据路由选择在employee模板显示相应的员工信息。

图5 程序页面

现在,我们完成了Employee程序的基本功能了,提供用户查下员工的信息了。

1.1.3 总结

本文通过Demo例子介绍了Ember的使用,主要介绍了Ember的模型,控制器、模板和路由,由于Ember是Javascript MVC框架,而且作为初学者很容易困惑于它的自动生成和默认规则,所以我极力推荐大家要仔细看一遍RoutingController的官方文档。

我们通过介绍Ember的Handlerbars模板引擎,定义了Demo程序的页面,然后通过路由控制器定义路由行为,根据路由行为选择控制器,控制器负责数据加载和显示。但我们的例子中还没有设计的Ember视图模块,如果想进一步学习请参考官方文档或书籍。

参考

http://www.cnblogs.com/rush/archive/2013/04/29/3051191.html

【JavsScript】Ember.js,布布扣,bubuko.com

时间: 2024-10-14 01:57:55

【JavsScript】Ember.js的相关文章

【JavsScript】JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember

摘要:选择JavaScript MVC框架很难.一方面要考虑的因素非常多,另一方面这种框架也非常多,而要从中选择一个合适的,还真得费一番心思.本文对JavaScript MVC框架Angular.Backbone.CanJS和Ember作了比较,供大家参考. 选择JavaScript MVC框架很难.一方面要考虑的因素非常多,另一方面这种框架也非常多,而要从中选择一个合适的,还真得费一番心思.想知道有哪些JavaScript MVC框架可以选择?看看 TodoMVC吧. 我用过其中4个框架:An

【JavsScript】JavaScript MVC 框架技术选型

你很喜欢Gmail和Trello之类的单页面应用,但是不太确定该从何开始.也许你的JavaScript代码是如此的杂乱无章,以致于你很想在下一个项目上尝试下JavaScript MVC库和框架,却苦于没有头绪?我正在撰写一本单页面应用的书,所以我阅读了大量网上的相关资料.在这里我尝试提供一些看法,希望可以帮助你下决定. 简介 这里讨论的是时下最热的框架,AngularJS.Backbone.Ember和Knockout.同时提到了Batman.CANjs.Meteor和Spine,但是没有详细展

【JavsScript】父子页面之间跨域通信的方法

由于同源策略的限制,JavaScript跨域的问题,一直是一个比较棘手的问题,为了解决页面之间的跨域通信,大家煞费苦心,研究了各种跨域方案.之前也有小网同学分享过一篇“跨域,不再纠结” 开始照着尝试时还是有些不够明白的地方,深入了解之后,这里给大家补充一点更具体的做法. 先来看看哪些情况下才存在跨域的问题: 其中编号6.7两种情况同属于主域名相同的情况,可以设置domain来解决问题,今天就不讨论这种情况了. 对于其他跨域通信的问题,我想又可以分成两类: 其一(第一种情况)是a.com下面的a.

【JavsScript】好用的高质量 JavaScript 库一览

http://www.oschina.net/news/26706/list-of-highly-useful-javascript-libraries-for-developers 用headjs来管理和加载js [JavsScript]好用的高质量 JavaScript 库一览,布布扣,bubuko.com

【JavsScript】推荐五款流行的JavaScript模板引擎

摘要:Javascript模板引擎作为数据与界面分离工作中最重要一环,受到开发者广泛关注.本文通过开发实例解析五款流行模板引擎:Mustache.Underscore Templates.Embedded JS Templates.HandlebarsJS.Jade templating. 近日一位20岁的开发者Jack Franklin在<The top 5 JavaScript templating engines>一文中向开发者们推荐了5款流行的JavaScript模板引擎.下面为该文的

【修改】纯JS省市区三级联动 支持js默认省市区

---恢复内容开始--- <!DOCTYPE html><html><head><title>修改,QQ JS省市区三级联动 -支持默认省市区</title><!-- 使用QQ的省市区数据 --><!--<script type="text/javascript" src="http://ip.qq.com/js/geo.js"></script>--><

【翻译】Ext JS最新技巧——2014-5-12

原文:http://www.sencha.com/blog/top-support-tips-may-2014?mkt_tok=3RkMMJWWfF9wsRoluazJZKXonjHpfsX77OQlXK%2B%2FlMI%2F0ER3fOvrPUfGjI4AT8NjI%2BSLDwEYGJlv6SgFSbfBMbdlybgMWRA%3D Seth Lemmons:为网格行设置不同的高度 在整个网格中,行高通常都会保持为同一高度.然而,这并不适用于所有情形,有时候需要根据单元格中的数据来自动调整

【JavsScript】Spine的作者曾经是Backbone的作者

基于MVC的JavaScript Web富应用开发 Alex MacCaw,是一名Ruby/JavaScript程序员,在开源社区中很有名望,是Spine框架的作者,开发过Taskforce,Socialmod等大型开源项目,同时活跃在纽约.旧金山和柏林的各大Ruby/Rails会议. 第11章 Spine类库 设置 类 实例化 类扩展 上下文 事件 模型 获取记录 模型事件 校验 持久化 控制器 代理 元素 委托事件 控制器事件 全局事件 渲染模式 元素模式 构建联系人管理应用 联系人模型 侧

【翻译】Ext JS 5的平板支持

原文:Ext JS 5 Tablet Support Ext JS已被公认为桌面Web应用程序的领先框架.自从平板开始在全球挑战PC的销售,无论是个人还是企业,电脑横向的应用已经产生急剧的变化.Sencha意识到了这种变化,并推出了包含新功能和进行优化了的Ext JS 5. Ext JS从Sencha Touch 2学到了一些新把戏.多年最好的移动Web应用程序框架经验的沉淀要应对现代平板电脑上的桌面显示,那是卓卓有余的.通过类系统.事件管理.窗口小部件和新的部署选项就可以了解到这些更新. 除了