5.8 Components — Composing Components(组合组件)
一、概述
当你通过和另外一个组件组合的时候,组件就会真正发挥它们的所有潜能。比如<ul>元素,只有<li>元素是适合作为它的子元素的。如果我们希望同样类型的行为,那么我们就必须组合组件。
就像我们组合HTML元素一样,我们可以以同样的方式用于组件。
app/templates/application.hbs
{{#user-list users=activeUsers sortBy='name' as |user|}}
{{user-card user=user}}
{{/user-list}}
二、Component Blocks
组件可以以两种形式被使用,就像一般的HTML元素一样。
1. Inline Form
app/templates/application.hbs
{{user-list users=activeUsers}}
这是基本的非块级的组件,这不提供给用户将自己的内容插入到给定的组件的能力。
2. Block Form
app/templates/application.hbs
{{#user-list users=activeUsers}}
{{!-- custom template here --}}
{{/user-list}}
(1) 为了组合组件,我们必须使用block形式,但是我们也必须能够区分我们的组件它使用的是哪种形式。这可以通过使用在组件中的hasBlock属性做到。
app/templates/components/user-list.hbs
{{#if hasBlock}}
{{yield}}
{{else}}
<p>No Block Specified</p>
{{/if}}
一旦我们知道组件使用的是block格式,我们可以通过使用{{yield}}辅助器把用户放在block中的任何内容填充到我们希望展现的地方。
(2) {{yield}}辅助器在组件的模板中可以被使用多次,允许我们创建一个像list一样工作的组件,这里我们输出一个标题并且为每个post产生内容。
app/templates/components/post-list.hbs
{{#each posts as |post|}}
<h3>{{post.title}}</h3>
<p>{{yield}}</p>
{{/each}}
可像这样被使用:
app/templates/posts.hbs
{{#post-list posts=headlinePosts}}
Greatest post ever!
{{/post-list}}
生成的HTML:
<div id="ember123" class="ember-view">
<h3>Tomster goes to town</h3>
<p>Greatest post ever!</p>
<h3>Tomster on vacation</h3>
<p>Greatest post ever!</p>
</div>
但是难道只是使用它一遍又一遍输出相同的东西吗?难道我们不想自定义我们的posts并且展示正确的内容吗?我们当然想。让我们稍微探索一下{{yield}}辅助器。
三、Data Down
1. 为了完成组合性的模板,我们需要向这些模板传递数据。可以使用上面介绍的{{yield}}辅助器来实现。
2. 正如我们在前一节看到的,组件的块中定义的内容将会被生产到组件的layout,{{yield}}就定义在这个地方。除此之外,{{yield}}辅助器也允许我们发送数据通过生产参数回到我们调用的组件的作用域。
{{yield}}
{{yield "post"}}
{{yield item}}
{{yield this "footer"}}
3. 默认的yield不会发送任何数据,但是你可以提供任意数量的参数。此外,所得到的值是按顺序排列的,由于组件暴露它们所以你可以以相同的顺序获取它们。发送数据允许组件的用户使用这个数据。对于用户去获取数据,他需要知道组件暴露了什么数据,这就是文档如此重要,并且从那里产生的数据可以用操作符来访问。让我们看一个例子:
app/components/user-list/template.hbs
{{#each users as |user|}}
{{yield user}}
{{/each}}
这个{{user-list}}组件会像它的用户一样被产生多次。我们可以通用下面的方法来消除它。
app/users/template.hbs
{{#user-list users=users as |user|}}
{{user-card user=user}}
{{/user-list}}
现在{{user-card}}获取到当前用户,因为{{yield user}}是在{{each}}块内,当{{user-list}}遍历每个用户时发生改变。虽然这很好,如果我们使用我们的组件不包含一个block,例如{{user-list users=users}}会怎样呢?这样会使组件近乎无用因为没有产生任何东西,但是users仍然被遍历。
4. 让我们混合hasBlock属性并且看是否我们可以使它更有用。
app/components/user-list/template.hbs
{{#if hasBlock}}
{{#each users as |user|}}
{{yield user}}
{{/each}}
{{else}}
{{#each users as |user|}}
<section class="user-info">
<h3>{{user.name}}</h3>
<p>{{user.bio}}</p>
</section>
{{/each}}
{{/if}}
这使得我们的组件更有用,因为它有正常的默认值,但它也允许我们重写这些默认值。通过使用{{yield}}我们可以为用户传递我们的参数。这使得传递数据的概念非常有用。
四、{{component}} Help
1. 为了理解{{component}}辅助器,我们将为{{user-list}}增加下面的新功能:
- 对每个类型的用户,我们希望使用不同的layout。
- 这个列表也可以在基本和详细模式间切换。
2. 添加一个新类型的用户,一个超级用户,他将在我们的应用程序中有不同的行为。怎样使用新数据为不同类型去展现不同的UI呢?这就是{{component}}辅助器将要展示的。这个辅助器让我们能够在运行时选择一个组件。
3. 因为我们有两种用户,'public'和'superuser',并且我们希望为每一个类型渲染一个组件加上简单和详细两种模式。我们有下面这些组件名:
basic-card-publicbasic-card-superuserdetailed-card-publicdetailed-card-superuser
我们可以创建这些名字通过使用嵌套形式的{{contact}}辅助器:
{{component (concat 'basic-card-' user.type)}}
现在我们的组件名字是有效的,因为使用了破折号,我们可以把两种模式放在一起组成一个完整的模板。
app/users/template.hbs
{{#user-list users=users as |user basicMode|}}
{{#if basicMode}}
{{component (concat 'basic-card-' user.type) user=user}}
{{else}}
{{component (concat 'detailed-card-' user.type) user=user}}
{{/if}}
{{/user-list}}
- 现在我们根据user.type等于'superuser'和'public'把
{{basic-card-superuser}}和{{detailed-card-public}}加载到相应的位置。 - 使用嵌套在form中的'concat'辅助器允许我们这样实现。
- 嵌套的辅助器在父辅助器前进行评估,然后该辅助器可以使用嵌套的辅助器返回的值。
- 在这种情况下,只是连续的两个值。你还可以在嵌套的form中实验其他的辅助器,比如if辅助器。
4. 除了使用{{component}},对于basic/detailed模式的功能我们也有第二个产生的值,我们已经添加到yield中,例如{{yield user basic}}。
5. 用户可以决定如何命名产生的值。我们可以像这样命名:
app/users/template.hbs
{{#user-list users=users as |userModel isBasic|}}
{{! something creative here }}
{{/user-list}}
五、Actions Up
1. 现在我们知道了如何发送数据,我们可能想通过一些用户交互来处理数据,比如改变用户的头像。我们可以通过actions来完成这个。
2. 我们将会查找一个{{user-profile}}组件去实现一个save action。通过产生action作为一个参数,允许用户在不需要如何保存的情况下使用组件,但是依旧能触发save。
app/components/user-profile/component.js
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
saveUser() {
var user = this.get('user');
user.save()
.then(() => {
this.set('saved', true);
})
.catch(error => {
this.set('saveError', error);
});
}
}
});
app/components/user-profile/template.hbs
{{! most likely we have some markup here }}
{{yield profile (action "saveUser")}}
3. 所以现在用户将会获取我们定义的data和action。让我们看一下组件是如果作为块的形式被消耗的。
app/templates/user/profile.hbs
{{#user-profile user=user as |profile saveUser|}}
{{user-avatar url=profile.imageUrl onchange=saveUser}}
{{/user-profile}}
可以从这个例子中看出,用户可以可以hook到{{user-profile}}组件的saveUser action,它被我们嵌入的辅助器(action "saveUser")传递。这个辅助器读取一个不在当前上下文的actions hash中的属性,然后通过这个函数创建一个闭包并且传递参数。
4. 我们也可以利用这个格式把action放在本机HTML元素(如输入按钮):
{{#user-profile user=user as |profile saveUser|}}
<button type="button" onclick={{action saveUser}}>Save</button>
{{/user-profile}}
这是非常有用的,因为我们重用这些元素提供的 event hooks。这使得组件更加重用,因为我们可以组合小的组件更好的做一件事。
六、Wrapping Up
组合组件是关于分割功能为可重用的块,这样可以更容易的退出并且更容易的结合在一起,以便与他们一起很好的工作。这也可以被更容易的测试,因为我们试着避免单片组件做所有单片组件事,我们把功能分割为小的部分。
5.8 Components — Composing Components(组合组件)的更多相关文章
- 【原创】开源.NET排列组合组件KwCombinatorics使用(三)——笛卡尔积组合
本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...
- 【原创】开源.NET排列组合组件KwCombinatorics使用(二)——排列生成
本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...
- 【原创】开源.NET排列组合组件KwCombinatorics使用(一)—组合生成
本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...
- Web Components实践开发Tab组件
本文是对web components的一次实践,最终目的是做出一个tab组件,本文涉及Custom Elements(自定义元素).HTML Imports(HTML导入).HTML Template ...
- Svelte入门——Web Components实现跨框架组件复用
Svelte 是构建 Web 应用程序的一种新方法,推出后一直不温不火,没有继Angular.React和VUE成为第四大框架,但也没有失去热度,无人问津.造成这种情况很重要的一个原因是,Svelte ...
- Unattended Setup Software Components (无人值守安装软件组件)
原文 http://social.technet.microsoft.com/Forums/windows/en-US/d4ad85b4-8342-4401-83ed-45cefa814ec5/una ...
- Svelte入门——Web Components实现跨框架组件复用(二)
在上节中,我们一起了解了如何使用Svelte封装Web Component,从而实现在不同页面间使用电子表格组件. Svelte封装组件跨框架复用,带来的好处也十分明显: 1.使用框架开发,更容易维护 ...
- Ionic4.x 中的 UI 组件(UI Components)表单相关组件
1.ion-input 单行文本框 2.ion-toggle 开关 3.ion-radio-group.ion-radio 单选按钮组 4.ion-checkbox 多选按钮组 5.ion-selec ...
- 前端组件化-Web Components【转】
以下全部转自:http://www.cnblogs.com/pqjwyn/p/7401918.html 前端组件化的痛点在前端组件化横行的今天,确实极大的提升了开发效率.不过有一个问题不得不被重视,拟 ...
随机推荐
- angularjs基础——变量绑定
1)弄一个ng-app(angularjs 应用) 2)在里面用ng-model(angularjs 模型)就可以定义一个模型变量 3)使用模版方法就可以输出变量了(例如:{{name}}) 示例: ...
- 在linux中添加环境变量
首先用命令查看配置了哪些环境变量 env命令查看 编辑环境变量命令 vim ~/.bash_profile Counter_HOME=/home/test/Counterexport Counter ...
- Python 流程控制:for
for 循环用于对一个序列进行遍历,用法如下: In [4]: for i in 'abcd': ...: print(i) ...: a b c d In [13]: for i in range( ...
- Lua脚本和C++交互(二)
上一节讲了一些基本的Lua应用,下面,我要强调一下,Lua的栈的一些概念,因为这个确实很重要,你会经常用到.熟练使用Lua,最重要的就是要时刻知道什么时候栈里面的数据是什么顺序,都是什么.如果你能熟练 ...
- CentOS 下使用yum 命令安装MySQL
CentOS Linux下使用yum 命令安装MySQL过程记录. 1. 查看服务器中有没有安装过MySQL 1. 查看有没有安装包: yum list mysql* #移除已经安装的mysql yu ...
- ExtJS 6.2 基础使用
一. 安装: 下载两个压缩包:分别是 ext-6.2.0-gpl(这个是ExtJS 的SDK文件,创建新项目的时候需要用). SenchaCmd-6.5.2-windows-64bit (这个下载下来 ...
- poj_1037 动态规划+字典序第k大
题目大意 给定n个数字,规定一种 cute 排序:序列中的数字大小为严格的波浪形,即 a[0] > a[1] < a[2] > a[3] < .... 或者 a[0] < ...
- MQTT协议笔记之消息流
前言 前面的笔记已把所有消息类型都过了一遍,这里从消息流的角度尝试解读一下. 网络故障 在任何网络环境下,都会出现一方连接失败,比如离开公司大门那一刻没有了WIFI信号.但持续连接的另一端-服务器可能 ...
- devstack with neutron 参考文献
http://networkstatic.net/installing-openstack-ml2-neutron-plugin-devstack-fedora/ https://wiki.opens ...
- CentOS下安装cvechecker并进行主机基线安全检查
一.cvechecker的安装 1.首先下载cvechecker并解压该文件: cd /home/username mkdir cve wget https://raw.githubuserconte ...