• [译] 第二十四天: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

  • 相关阅读:
    bzoj3676 [Apio2014]回文串
    bzoj4199 [Noi2015]品酒大会
    bzoj3171 [Tjoi2013]循环格
    bzoj4709 [Jsoi2011]柠檬
    bzoj2668 [cqoi2012]交换棋子
    bzoj1458 士兵占领
    25号搜索的一些例子,。。Oil Deposits&&Red and Black&&Knight Moves&&Catch That Cow&&Tempter of the Bone
    第一次超水(我错了,有难度的)的组队赛!!!The Coco-Cola Store &&Multiple of 17&& Box Game
    博弈 7月24号:HDU 2176(Nim博弈)
    2013年7月23号:大数的加与乘I-number&&Power of Cryptography
  • 原文地址:https://www.cnblogs.com/endless-on/p/3517851.html
Copyright © 2020-2023  润新知