[译] 第二十四天:Yeoman Ember - 缺失的指南

前言

到目前为止 ,这个系列我们探讨了Bower, AngularJS, GruntJS, PhoneGap, Meteor, EmberTimelineJS JavaScript技术。今天的30天挑战,我决定学习一款叫Yeoman的高效前端开发工具。本文,我们先了解Yeoman基础,然后用Yeoman开发一个Ember应用,这里不再讲EmberJS基础,你可参考第19天的博客。 

 

什么是Yeoman?

Yeoman是一个开源的高效客户端开发工具,它集成了工具和框架,有助于开发者快速高效并遵循最好的用户体验构建web应用。它的灵感来自Ruby on Rails 概念。Yeoman包含三个工具:

  1. Yo: 一个基架工具,当你需要开始新项目时为你生成所有架构模板,它避免了样板代码,利于开始新项目和配置grunt任务。
  2. Grunt: 基于JavaScript的命令行构建工具,帮你自动完成需要重复的任务。你可以把它看作JavaScript的Make或者Ant. 它可以执行像压缩,编译,单元测试,代码审查等任务,详细内容参考第5天关于GruntJS的博客。
  3. Bower: 客户端包管理工具,可用作搜索,安装,卸载web资源如JavaScript, HTML和CSS. 它不是一款封闭的工具,为使用这种技术的开发者提供了大量选择。详细内容参考第1天关于Bower的博客。 

我为什么关注Yeoman?

如果你要说服自己学习Yeoman, 可以看看它网站上whyyeoman部分。 

前提准备

安装Yeoman之前先安装:

  1. Node: Yeoman需要NPM. NPM是一个node包管理,绑定在Nodejs安装中,所以,请从 http://nodejs.org 下载最新的node.js.
  2. Git: 需要git来从git仓库获取有些包的代码,所以,安装git

安装Yeoman

准备条件做好后,你可以输入以下命令安装yeoman.

$ npm install -g yeoman
View Code

以上命令会全局安装yeoman, -g 代表全局安装,如果你还没装Grunt和bower, 这也会给你安装好。 

安装Yeoman Ember Generator

Yeoman依赖Generators完成web基架,对现代JavaScript MV*框架有多种generators, 我们用Ember generator. NPM用于安装generators.

$ npm install -g generator-ember.
View Code

程序用例

本文我们开发个网摘程序允许用户发布和分享链接,你可以查看在线程序,和第19天的一样,可以参考之前的用例来了解。 

Github仓库

今天的demo放在 github: day24-yeoman-emberjs-demo. 

创建Ember程序

讲完基础后我们来开始开发程序。 

在机器上新建目录,更改程序目录。

$ mkdir getbookmarks

$ cd getbookmarks
View Code

然后运行yo ember, 它会问你是否想用Twitter Bootstrap, 一般我的程序都用它,所以我输入Yes.

$ yo ember

 

     _-----_

    |       |

    |--(o)--|   .--------------------------.

   ---------  |    Welcome to Yeoman,    |

    ( __ )   |   ladies and gentlemen!  |

    /___A___\   '__________________________'

     |  ~  |

   __'.___.'__

 

 

[?] Would you like to include Twitter Bootstrap for Sass? Yes
View Code

输入yes后,Yeoman会给出Ember程序架构,自动运行bower和npm安装程序所需的依赖。 

来看看Yeoman生成的Ember程序,这个程序有三个顶层目录:app, node_modules, test. 还有配置文件--.bowerrc, .gitignore, .jshintrc, Gruntfile.js, package.json. 程序结构如图。

 

所有程序特定代码都砸app目录,这个程序架构遵循Ember最佳体验。

 

  1. Bower_components目录存放所有客户端依赖,如Ember, Twitter Boostrap等,Bower在这个文件夹安装所有依赖,这个路径可以改到 .bowerrc文件夹。
  2. images目录存放所有特定图片,Yeoman优化这个目录的所有图片。
  3. Index.html文件包含所有ember.js依赖并按序排列,所有bootstrap依赖,和Gruntfile.js用于替换(或者移除)引用到non-optimized脚本或者HTML文件里的格式表单的'build'注释。
  4. scripts目录包含所有Ember程序控制器,视图,模型和路由。
  5. styles目录有程序指定的css文件,这个css导入bootstrap格式。
  6. templates目录包含程序handlebar模板。 

现在,运行启动内嵌的预览服务器,grunt服务器采用我第7天讲到的livereload.

$ grunt server
View Code

这会在默认浏览器里打开程序。

 

生成Story模型

第19天开发的GetBookmarks程序有一个Ember模型叫Story,Yeoman subgenerator可用于生成更小的Story模型,要生成Story模型,执行以下命令。

$ yo ember:model Story
View Code

输出如下。

create app/scripts/models/story_model.js
   invoke   ember:controller:/usr/local/lib/node_modules/generator-ember/model/index.js
   create     app/scripts/controllers/stories_controller.js
   create     app/scripts/controllers/story_edit_controller.js
   create     app/scripts/routes/stories_route.js
   create     app/scripts/routes/story_route.js
   create     app/scripts/routes/story_edit_route.js
   invoke       ember:view:/usr/local/lib/node_modules/generator-ember/controller/index.js
   create         app/scripts/views/story_view.js
   create         app/scripts/views/story_edit_view.js
   create         app/scripts/views/stories_view.js
   create         app/templates/story.hbs
   create         app/templates/story_edit.hbs
   create         app/templates/stories.hbs
   create         app/scripts/views/bound_text_field_view.js
   invoke       ember:router:/usr/local/lib/node_modules/generator-ember/controller/index.js
 conflict         app/scripts/router.js
[?] Overwrite app/scripts/router.js? overwrite
    force         app/scripts/router.js
View Code

这会在app/scripts/models 目录下生成story_model.js, 连同还生成相应的视图,控制器和路由。如果你对此不太了解可参照我第19天的博客。 

用以下代码更新story_model.

Emberapp.Story = DS.Model.extend({
  url : DS.attr('string'),
    tags : DS.attr('string'),
    fullname : DS.attr('string'),
    title : DS.attr('string'),
    excerpt : DS.attr('string'),
    submittedOn : DS.attr('date')
});
View Code

请重启Grunt 服务器以使改动生效。 

安装Ember LocalStorage适配器

我们用HTML 5 LocalStorage存储数据,用bower安装适配器。

$ bower install --save ember-localstorage-adapter
View Code

然后更新index.html依赖

<script src="bower_components/ember-localstorage-adapter/localstorage_adapter.js"></script>
View Code

同时用以下代码更新app/scripts/store.js.这会用LSAdapter(Local Storage Adapter)而不是FixtureAdapter配置程序。

Getbookmarks.Store = DS.Store.extend();
Getbookmarks.ApplicationAdapter = DS.LSAdapter.extend({
  namespace: 'stories'
});
View Code

更新路由

用以下代码替换router.js.

Getbookmarks.Router.map(function () {
  this.resource('index',{path : '/'});
  this.resource('story', { path: '/story/:story_id' });
  this.resource('story_edit', { path: '/story/new' });
});
View Code

以上代码,我们定义了三个路由。

  1. index路由对应的根路径。
  2. 查看独立文章用story路由。
  3. 用story_edit路由新建文章,当用户查看'#/story/new', 一个表格会显示给用户。 

提交新Story

现在添加表格,用于用户打开'#/story/new'时显示,用以下代码更新 app/templates/story_edit.hbs. 

<form class="form-horizontal" role="form">
      <div class="form-group">
        <label for="title" class="col-sm-2 control-label">Title</label>
        <div class="col-sm-10">
          <input type="title" class="form-control" id="title" name="title" placeholder="Title of the link" required>
        </div>
      </div>
      <div class="form-group">
        <label for="excerpt" class="col-sm-2 control-label">Excerpt</label>
        <div class="col-sm-10">
          <textarea class="form-control" id="excerpt" name="excerpt" placeholder="Short description of the link" required></textarea>
        </div>
      </div>
      <div class="form-group">
        <label for="url" class="col-sm-2 control-label">Url</label>
        <div class="col-sm-10">
          <input type="url" class="form-control" id="url" name="url" placeholder="Url of the link" required>
        </div>
      </div>
      <div class="form-group">
        <label for="tags" class="col-sm-2 control-label">Tags</label>
        <div class="col-sm-10">
          <textarea id="tags" class="form-control" name="tags" placeholder="Comma seperated list of tags" rows="3" required></textarea>
        </div>
      </div>
      <div class="form-group">
        <label for="fullname" class="col-sm-2 control-label">Full Name</label>
        <div class="col-sm-10">
          <input type="text" class="form-control" id="fullname" name="fullname" placeholder="Enter your Full Name like Shekhar Gulati" required>
        </div>
      </div>
      <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
          <button type="submit" class="btn btn-success" {{action 'save'}}>Submit Story</button>
        </div>
      </div>
  </form>
View Code

现在打开 http://localhost:9000/#/story/new 可以看到提交表格。 

更新 StoryEditController save功能,会把文章保存到本地存储中。

Getbookmarks.StoryEditController = Ember.ObjectController.extend({
  save: function(){
    var url = $('#url').val();
        var tags = $('#tags').val();
        var fullname = $('#fullname').val();
        var title = $('#title').val();
        var excerpt = $('#excerpt').val();
        var submittedOn = new Date();
        var store = this.get('store');
        console.log('Store .. '+store);
        var story = store.createRecord('story',{
            url : url,
            tags : tags,
            fullname : fullname,
            title : title,
            excerpt : excerpt,
            submittedOn : submittedOn
        });
    story.save();
    this.transitionToRoute('index');
  }
});
View Code

列出所有文章

接下来的功能是实现在侧边栏显示文章列表。 

在application_route.js, 我们会从本地存储中获取所有文章。

Getbookmarks.ApplicationRoute = Ember.Route.extend({
    model : function(){
        var stories = this.get('store').findAll('story');
        return stories;
    }
});
View Code

接下来更新application.hbs加载文章标题和链接,用以下代码更新。

<div>
    <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">GetBookmarks</a>
        </div>
        <div class="collapse navbar-collapse navbar-ex1-collapse">
            <ul class="nav navbar-nav pull-right">
                <li>{{#link-to 'story_edit'}}<span class="glyphicon glyphicon-plus"></span> Submit Story{{/link-to}}</li>
            </ul>
        </div>
    </nav>
    <div class="container" id="main">
        <div class="row">
            <div>
                <div class="col-md-3">
                    <div class="well sidebar-nav">
                        <table class='table'>
                          <thead>
                            <tr><th>Recent Stories</th></tr>
                          </thead>
                          {{#each controller}}
                            <tr><td>
                            {{#link-to 'story' this}}
                              {{title}}
                            {{/link-to}}
                            </td></tr>
                          {{/each}}
                        </table>
                    </div>
                </div>
                <div class="col-md-9">
                    {{outlet}}
                </div>
            </div>
        </div>
    </div>
</div>
View Code

程序界面会重新加载更新。 

查看单独文章

最后一个功能是当用户打开 http://localhost:9000/#/story/:id 会显示单独的文章,:id对应文章id, 用以下代码更新story_route.js.

Getbookmarks.StoryRoute = Ember.Route.extend({
  model : function(params){
        var store = this.get('store');
        return store.find('story',params.story_id);
  }
});
View Code

用以下代码更新 app/templates/story.hbs.

<h1>{{title}}</h1>
<h2> by {{fullname}} <small class="muted">{{submittedOn}}</small></h2>
{{#each tagnames}}
  <span class="label label-primary">{{this}}</span>
{{/each}}
<hr>
<p class="lead">
      {{excerpt}}
</p>
View Code

构建产品

最后,运行grunt build命令生成一个分布式程序,grunt build命令使用app目录下的源代码文件,返回到dist下的分布式程序中。

$ grunt build
View Code

这就是今天的内容,继续给反馈吧。 

原文:https://www.openshift.com/blogs/day-24-yeoman-ember-the-missing-tutorial

posted on 2014-01-13 18:04  百花宫  阅读(766)  评论(0编辑  收藏  举报