文档章节

从服务器获取数据,引入组件

ubuntuvim
 ubuntuvim
发布于 2016/04/26 23:22
字数 1967
阅读 73
收藏 0

博文原址:http://blog.ddlisting.com/2016/04/21/yin-ru-zu-jian/

接着前面四篇:

  1. 环境搭建以及使用Ember.js创建第一个静态页面
  2. 引入计算属性、action、动态内容
  3. 模型,保存数据到数据库
  4. 发布项目,加入CRUD功能

清理模板,使用组件重构

2.0版本之后组件会越来越重要。有关组件的介绍请看Ember.js 入门指南之二十八组件定义。组件的创建同样可以使用Ember CLI命令创建。如下命令创建了2个组件,创建的同时会自动创建2个文件;一个是组件类(app/components/xxx.js)。一个是组件对应的模板(app/templates/components/xxx.hbs)。

ember g component library-item
ember g component library-item-form

修改模板library-item

下面在组件模板library-item.hbs中增加如下代码:

<!-- app/templates/components/library-item.hbs -->
<div class="panel panel-default library-item">
    <div class="panel-heading">
        <h3 class="panel-title">{{item.name}}</h3>
    </div>
    <div class="panel-body">
        <p>Address: {{item.address}}</p>
        <p>Phone: {{item.phone}}</p>
    </div>
    <div class="panel-footer text-right">
      {{yield}}
    </div>
</div>

如果注意看可以发现上述代码与app/templates/libraries/index.hbs文件的代码非常相似。这是item替代了model。至于item是怎么来的请看Ember.js 入门指南之二十九属性传递,这篇博文介绍了组件的属性传递,item是从调用组件的模板传递过来的。上述代码中还有一个重要的东西是{{yield}},这个表达式与{{outlet}}类似。同样也是一个占位符。组件渲染之后会被传进来的html代码替换。比如下面的调用代码:

{{#library-item item=model}}
  Closed
{{/library-item}}

组件渲染之后,上述的Closed会替换到{{yield}}这里,最终得到的html代码如下:

<div class="panel-footer text-right">
      Closed
</div>

有关组件渲染的内容请看Ember.js 入门指南之三十包裹内容

修改模板library-item-form

<!-- app/templates/components/library-item-form.hbs -->
<div class="form-horizontal">
    <div class="form-group has-feedback {{if item.isValid 'has-success'}}">
        <label class="col-sm-2 control-label">Name*</label>
        <div class="col-sm-10">
          {{input type="text" value=item.name class="form-control" placeholder="The name of the Library"}}
          {{#if item.isValid}}<span class="glyphicon glyphicon-ok form-control-feedback"></span>{{/if}}
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-2 control-label">Address</label>
        <div class="col-sm-10">
          {{input type="text" value=item.address class="form-control" placeholder="The address of the Library"}}
        </div>
    </div>
    <div class="form-group">
        <label class="col-sm-2 control-label">Phone</label>
        <div class="col-sm-10">
          {{input type="text" value=item.phone class="form-control" placeholder="The phone number of the Library"}}
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-default" {{action 'buttonClicked' item}} disabled="{{unless item.isValid 'disabled'}}">{{buttonLabel}}</button>
        </div>
    </div>
</div>

注意观察上述代码与libraries/new.hbslibraries/edit.hbs几乎是一样的。有点不一样的是把校验移到model中。比如校验name属性不为空。 注意:顶部导入的代码。

import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import Ember from 'ember';

export default Model.extend({
  name: attr('string'),
  address: attr('string'),
  phone: attr('string'),

  isValid: Ember.computed.notEmpty('name')
});

再修改app/templates/libraries/index.hbs引入组件。

<h2>List</h2>
<div class="row">
  {{#each model as |library|}}
    <div class="col-md-4">
      {{#library-item item=library}}
        {{#link-to 'libraries.edit' library.id class='btn btn-success btn-xs'}}Edit{{/link-to}}
        <button class="btn btn-danger btn-xs" {{action 'deleteLibrary' library}}>Delete</button>
      {{/library-item}}
    </div>
  {{/each}}
</div>

在迭代中使用组件,通过属性名item传递迭代出来的对象library到组件中。其中link-tobutton这两句代码会替换到组件library-item{{yield}}上。 等待项目重启完成,可以看到界面与之前的没有任何变化。页面是没有变化,但是后台的处理还需要完善。

修改app/templates/libraries/new.hbs

<!-- app/templates/libraries/new.hbs -->
<h2>Add a new local Library</h2>

<div class="row">

  <div class="col-md-6">
      {{library-item-form item=model buttonLabel='Add to library list' action='saveLibrary'}}
  </div>

  <div class="col-md-4">
      {{#library-item item=model}}
          <br/>
      {{/library-item}}
  </div>

</div>

修改app/templates/libraries/edit.hbs

<h2>Edit Library</h2>

<div class="row">
    <div class="col-md-6">
      {{library-item-form item=model buttonLabel='Save changes' action='saveLibrary'}}
    </div>

    <div class="col-md-4">
      {{#library-item item=model}}
        <br/>
      {{/library-item}}
    </div>

</div>

在组件类library-item-form.js增加对action的处理。

import Ember from 'ember';

export default Ember.Component.extend({
  buttonLabel: 'Save',

  actions: {

    buttonClicked(param) {
      this.sendAction('action', param);
    }

  }
});

合并edit.hbsnew.hbsform.hbs

原来的文件edit.hbsnew.hbs几乎是一样的,可以使用组件重构。

<!-- /app/templates/libraries/form.hbs -->
<h2>{{title}}</h2>

<div class="row">
    <div class="col-md-6">
      {{library-item-form item=model buttonLabel=buttonLabel action='saveLibrary'}}
    </div>

    <div class="col-md-4">
      {{#library-item item=model}}
        <br/>
      {{/library-item}}
    </div>

</div>

为了实现代码复用,首先把不同的部分定义成属性:titlebuttonLabel。默认情况下路由会渲染到同名的模板上,如果你想修改这个默认行为可以使用renderTemplate()方法。

使用方法renderTemplate()setupController()

API介绍

默认情况下路由会渲染到同名的模板上,我们使用方法renderTemplate()执行渲染的模板。比如下面的代码使用这个方法执行路由new渲染到模板libraries/form.hbs

// app/routes/libraries/new.js
import Ember from 'ember';

export default Ember.Route.extend({

  model: function () {
    return this.store.createRecord('library');
  },

  setupController: function (controller, model) {
    this._super(controller, model);

    controller.set('title', 'Create a new library');
    controller.set('buttonLabel', 'Create');
  },

  renderTemplate() {
    this.render('libraries/form');
  },

  actions: {

    saveLibrary(newLibrary) {
      newLibrary.save().then(() => this.transitionTo('libraries'));
    },

    willTransition() {
      let model = this.controller.get('model');

      if (model.get('isNew')) {
        model.destroyRecord();
      }
    }
  }
});

注意方法setupController()设置组件模板中的属性titlebuttonLabel的值。同样的在修改路由edit.js

// app/routes/libraries/edit.js
import Ember from 'ember';

export default Ember.Route.extend({

  model(params) {
    return this.store.findRecord('library', params.library_id);
  },

  setupController(controller, model) {
    this._super(controller, model);

    controller.set('title', 'Edit library');
    controller.set('buttonLabel', 'Save changes');
  },

  renderTemplate() {
    this.render('libraries/form');
  },

  actions: {

    saveLibrary(newLibrary) {
      newLibrary.save().then(() => this.transitionTo('libraries'));
    },

    willTransition(transition) {
      let model = this.controller.get('model');

      if (model.get('hasDirtyAttributes')) {
        let confirmation = confirm("Your changes haven't saved yet. Would you like to leave this form?");

        if (confirmation) {
          model.rollbackAttributes();
        } else {
          transition.abort();
        }
      }
    }
  }
});

使用组件重构之后可以删除app/templates/libraries/new.hbsapp/templates/libraries/edit.hbs,这两个文件不需要了。效果截图如下:

页面重构截图

使用组件nav-link-to重构<li><a></a></li>

知道组件如何使用之后我们继续重构项目代码,重构导航模板navbar.hbs的链接代码。使用Ember CLI命令创建组件。

ember g component nav-link-to

这次使用扩展的方式扩展一个组件类,扩展Ember内置的组件类LinkComponent,使用方法extend()扩展一个类。然后使用属性tagName指定渲染之后的标签。更多有关组件属性的介绍请看Ember.js 入门指南之三十一自定义包裹组件的HTML标签,当然你也可以参考网址的教程实现本文的需求。

// app/components/nav-link-to.js
import Ember from 'ember';

export default Ember.LinkComponent.extend({
  tagName: 'li'
});

注意:记得修改Ember.Component.extendEmber.LinkComponent.extend。组件模板很简单。

<!-- app/templates/components/nav-link-to.hbs -->
<a href="">{{yield}}</a>

最后在修改导航模板navbar.hbs为如下内容:

<!-- app/templates/navbar.hbs -->
<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#main-navbar">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      {{#link-to 'index' class="navbar-brand"}}Library App{{/link-to}}
    </div>

    <div class="collapse navbar-collapse" id="main-navbar">
      <ul class="nav navbar-nav">
            {{#nav-link-to 'index'}}Home{{/nav-link-to}}
            {{#nav-link-to 'libraries'}}Libraries{{/nav-link-to}}
            {{#nav-link-to 'about'}}About{{/nav-link-to}}
            {{#nav-link-to 'contact'}}Contact{{/nav-link-to}}
      </ul>

      <ul class="nav navbar-nav navbar-right">
          <li class="dropdown">
              <a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Admin<span class="caret"></span></a>
              <ul class="dropdown-menu">
                  {{#nav-link-to 'admin.invitation'}}Invitations{{/nav-link-to}}
                  {{#nav-link-to 'admin.contact'}}Contacts{{/nav-link-to}}
              </ul>
          </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

等待项目重启完成,可以看到界面与之前的没有任何变化,可以任意点击导航栏菜单且不会出错。效果截图如下:

最终结果截图

家庭作业

本篇的家庭作业就是好好理解组件!参考下面的文章认真学习、理解组件。

  1. Ember.js 入门指南之二十八组件定义
  2. Ember.js 入门指南之二十九属性传递
  3. Ember.js 入门指南之三十包裹内容
  4. Ember.js 入门指南之三十一自定义包裹组件的HTML标签
  5. Ember.js 入门指南之三十二处理事件
  6. Ember.js 入门指南之三十三action触发变化

<br> 为了照顾懒人我把完整的代码放在[GitHub](https://github.com/ubuntuvim/library-app)上,如有需要请参考参考。博文经过多次修改,博文上的代码与github代码可能有出入,不过影响不大!如果你觉得博文对你有点用,请在github项目上给我点个`star`吧。您的肯定对我来说是最大的动力!!

© 著作权归作者所有

ubuntuvim
粉丝 33
博文 76
码字总数 98477
作品 1
深圳
后端工程师
私信 提问
React SSR(服务器端渲染) 细微探究

最近看了下 相关的东西,这里记录一下相关内容 本文实例代码已经上传到 github,感兴趣的可参见 Basic | SplitChunkV 初识 React SSR 遵循 规范,文件的导入导出如下: 而我们通常所写的 代码...

清夜
02/27
0
0
HT for Web的HTML5树组件延迟加载技术实现

HT for Web的HTML5树组件有延迟加载的功能,这个功能对于那些需要从服务器读取具有层级依赖关系数据时非常有用,需要获取数据的时候再向服务器发起请求,这样可减轻服务器压力,同时也减少了...

xhload3d
2015/05/03
931
0
React使用新版Context构建组件树工具注入

一、仓库地址 本文章基于React@16.3.0,讲解我是如何使用新版Context api做工具注入的。github地址 二、为什么要向组件注入工具 打个比方,在一个组件树中,通常可能会有多个组件会使用到aja...

bug给我滚
2018/06/28
0
0
从头开始,彻底理解服务端渲染原理(8千字汇总长文)

大家好,我是神三元,这一次,让我们来以React为例,把服务端渲染(Server Side Render,简称“SSR”)学个明明白白。 part1:实现一个基础的React组件SSR 这一部分来简要实现一个React组件的S...

神三元
07/06
0
0
Ember.js 入门指南——model简介1

本篇内容较多,拆分为两篇! Ember官网用了大篇幅来介绍model,相比之前的controller简直就是天壤之别啊! 从本篇开始学习Ember的模型,这一章也是Ember基础部分的最后一章内容,非常的重要...

ubuntuvim
2015/10/17
487
0

没有更多内容

加载失败,请刷新页面

加载更多

全面兼容IE6/IE7/IE8/FF的CSS HACK写法

浏览器市场的混乱,给设计师造成很大的麻烦,设计的页面兼容完这个浏览器还得兼容那个浏览器,本来ie6跟ff之间的兼容是很容易解决的。加上个ie7会麻烦点,ie8的出现就更头疼了,原来hack ie...

前端老手
8分钟前
3
0
常用快递电子面单批量打印api接口对接demo-JAVA示例

目前有三种方式对接电子面单: 1.快递公司:各家快递公司逐一对接接口 2.菜鸟:支持常用15家快递电子面单打印 3.快递鸟:仅对接一次,支持常用30多家主流快递电子面单打印 目前也是支持批量打...

程序的小猿
11分钟前
5
0
Yii 框架中rule规则必须搭配验证函数才能使用

public $store_id;public $user_id;public $page;public $limit;public $list;public $mch_list;public $cart_id;public $is_community;public $shop_id;public $cart_typ......

chenhongjiang
13分钟前
2
0
Flutter使用Rammus实现阿里云推送

前言: 最近新的Flutter项目有“阿里云推送通知”的需求,就是Flutter的App启动后检测到有新的通知,点击通知栏然后跳转到指定的页面。在这里我使用的是第三方插件Rammus来实现通知的推送,之...

EmilyWu
14分钟前
38
0
Knative 实战:三步走!基于 Knative Serverless 技术实现一个短网址服务

短网址顾名思义就是使用比较短的网址代替很长的网址。维基百科上面的解释是这样的: 短网址又称网址缩短、缩短网址、URL 缩短等,指的是一种互联网上的技术与服务,此服务可以提供一个非常短...

阿里巴巴云原生
29分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部