本文由Edwin Reynoso和Nilson Jacques进行了同行评审。 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态!
组件是Ember应用程序的重要组成部分。 它们允许您定义自己的,特定于应用程序的HTML标记,并使用JavaScript来实现其行为。 从Ember 2.x开始,组件将替换视图和控制器 (已弃用),并且是构建Ember应用程序的推荐方法。
Ember的组件实现尽可能符合W3C的Web组件规范 。 自定义元素在浏览器中变得广泛可用后,应该很容易将Ember组件迁移到W3C标准并使其可用于其他框架。
如果您想了解有关为什么可路由组件替换控制器和视图的更多信息,请观看Ember核心团队成员 Yehuda Katz和Tom Dale的这段简短视频 。
为了深入了解Ember组件,我们将构建一个tab-switcher
小部件。 这将包括具有相关内容的一组选项卡。 单击一个选项卡将显示该选项卡的内容,并隐藏其他选项卡的内容。 很简单? 让我们开始。
与往常一样 ,如果您想在浏览器中尝试该代码,则可以在我们的GitHub存储库或Ember Twiddle上找到本教程的代码。
一个Ember组件由一个Handlebars模板文件和一个随附的Ember类组成。 仅当我们需要与组件进行额外交互时才需要实现此类。 组件的使用方式与普通HTML标签类似。 当我们构建标签切换器组件时,我们将能够像这样使用它:
{{tab-switcher}}{{/tab-switcher}}
Ember组件的模板文件位于目录app/templates/components
。 类文件位于app/components
。 我们使用所有小写字母命名Ember组件,并用连字符将单词分隔。 此命名是按照惯例进行的,因此我们避免了与将来的HTML Web组件的名称冲突。
我们的主要Ember组件将是tab-switcher
。 注意,我说的是主要组件,因为我们将有几个组件。 您可以将组件与其他组件结合使用。 您甚至可以将组件嵌套在另一个父组件中。 对于tab-switcher
,我们将具有一个或多个如下所示的tab-item
组件:
{{#each tabItems as |tabItem| }}
{{tab-item item=tabItem
setSelectedTabItemAction="setSelectedTabItem" }}
{{/each}}
如您所见,组件也可以像原生HTML元素一样具有属性。
要遵循此入门指南,您需要创建EMber 2.x项目。 就是这样:
使用npm安装Ember。 有关npm的教程,请参见此处 。
npm install -g ember-cli
在撰写本文时,它将引入版本1.13
ember -v
=> version: 1.13.8
接下来,创建一个新的Ember应用程序:
ember new tabswitcher
导航到该目录并编辑bower.json
文件,以包括最新版本的Ember,ember-data和ember-load-initializers:
{
"name": "hello-world",
"dependencies": {
"ember": "^2.1.0",
"ember-data": "^2.1.0",
"ember-load-initializers": "^ember-cli/ember-load-initializers#0.1.7",
...
}
}
回到终端运行:
bower install
Bower可能会提示您输入Ember的版本解析。 从提供的列表中选择2.1版本,并在其bower.json
加上一个感叹号,以将分辨率保持为bower.json
。
下一步启动Ember CLI的开发服务器:
ember server
最后,浏览至http:// localhost:4200 /并检查浏览器控制台的版本。
让我们使用Ember的内置生成器创建一个标签切换器组件:
ember generate component tab-switcher
这将创建三个新文件。 一个是我们HTML的Handlebars文件( app/templates/components/tab-switcher.hbs
),第二个是我们组件类的JavaScript文件( app/components/tab-switcher.js
),最后一个是测试文件( tests/integration/components/tab-switcher-test.js
)。 测试组件超出了本教程的范围,但是您可以在Ember网站上阅读有关该组件的更多信息 。
现在运行ember server
以加载服务器并导航到http:// localhost:4200 / 。 您应该会看到一条标题为“欢迎使用Ember”的欢迎消息。 那么为什么我们的组件不显示呢? 好吧,我们还没有使用过,所以现在就开始使用。
打开应用程序模板app/templates/application.hbs
。 在h2
标签之后添加以下内容以使用该组件。
{{tab-switcher}}
在Ember中,组件有两种使用方式。 第一种方法称为内联表单 ,它是在没有任何内容的情况下使用它们。 这就是我们在这里所做的。 第二种方法称为块形式 ,它允许向组件传递一个Handlebars模板,该模板将在出现{{yield}}
表达式的位置的组件模板内呈现。 在本教程中,我们将坚持使用内联表单。
但是,这仍然没有在屏幕上显示任何内容。 这是因为组件本身没有任何要显示的内容。 我们可以通过将以下行添加到组件的模板文件( app/templates/components/tab-switcher.hbs
)中来进行更改:
<p>This is some content coming from our tab switcher component</p>
现在,当页面重新加载时(应该自动发生),您将看到上面显示的文本。 激动人心的时刻!
现在我们已经设置了主要的tab-switcher
组件,让我们创建一些tab-item
组件以嵌套在其中。 我们可以创建一个新的tab-item
组件,如下所示:
ember generate component tab-item
现在将新组件的把手文件( app/templates/components/tab-item.hbs
)更改为:
<span>Tab Item Title</span>
{{yield}}
接下来,让我们在主要的tab-switcher
组件内嵌套三个tab-items
。 将tab-switcher
模板文件( app/templates/components/tab-switcher.hbs
)更改为:
<p>This is some content coming from our tab switcher component</p>
{{tab-item}}
{{tab-item}}
{{tab-item}}
{{yield}}
如上所述, yield
帮助器将呈现传递到我们组件中的所有Handlebars模板。 但是,仅当我们以其块形式使用tab-switcher
,这才有用。 由于不是,所以我们可以完全删除yield
助手。
现在,当我们查看浏览器时,我们将看到三个tab-item components
,都说“ Tab Items Title”。 我们的组件现在是静态的,因此让我们添加一些动态数据。
当Ember应用程序启动时, 路由器负责显示模板,加载数据以及设置应用程序状态。 通过将当前URL与您定义的路由进行匹配来实现。 让我们为应用程序创建一条路由:
ember generate route application
对命令行问题回答“否”,以避免覆盖现有的application.hbs
文件。 这还将生成一个文件app/routes/application.js
。 打开它并添加一个模型属性:
export default Ember.Route.extend({
model: function(){
});
});
模型是一个对象,代表您的应用程序提供给用户的基础数据。 用户期望看到的任何内容均应由模型表示。 在这种情况下,我们会将选项卡的内容添加到模型中。 为此,请按照以下方式更改文件:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
var tabItems = [
{
title: 'Tab 1',
content: 'Some exciting content for the tab 1'
},
{
title: 'Tab 2',
content: 'Some awesome content for the tab 2'
},
{
title: 'Tab 3',
content: 'Some stupendous content for the tab 3'
}
];
return tabItems;
}
});
然后将tab-switcher
模板文件( app/templates/components/tab-switcher.hbs
)更改为:
{{#each tabItems as |tabItem| }}
{{tab-item item=tabItem }}
{{/each}}
接下来,将tab-item
模板文件( app/templates/components/tab-item.hbs
)的内容更改为:
<span>{{item.title}}</span>
{{yield}}
最后,将application.hbs
文件中的tab-switcher
用法更改为:
{{tab-switcher tabItems=model}}
这演示了如何将属性传递给组件。 我们已经使tab-item
组件模板可以访问item
属性。 页面刷新后,您现在应该看到选项卡项目标题反映了来自模型的数据。
现在,确保当用户单击tab-item
标题时,我们将显示该tab-item
的内容。 将tab-switcher
模板文件( app/templates/components/tab-switcher.hbs
)更改为:
{{#each tabItems as |tabItem| }}
{{tab-item item=tabItem setSelectedTabItemAction="setSelectedTabItem" }}
{{/each}}
<div class="item-content">
{{selectedTabItem.content}}
</div>
此更改假定我们在tab-switcher
组件上具有tabItem
属性。 此属性表示当前选择的tab-item
。 我们目前没有任何此类属性,因此让我们进行处理。
在常规模板中,操作会冒泡到控制器。 在组件模板内部,该操作会上升到组件的类。 它不会使层次结构进一步冒泡。
我们需要一种将点击操作发送到tab-switcher
组件的方法。 单击其任何子tab-item
组件后,应该会发生这种情况。 记得我曾说过,操作被发送到组件的类,而不是进一步到达层次结构。
因此,似乎不可能有任何来自子组件的动作到达父组件。 不用担心,因为这只是组件的默认行为,并且有一种变通方法来规避它。
一种简单的解决方法是将操作添加到tab-switcher
模板( app/templates/components/tab-switcher.hbs
),如下所示:
{{#each tabItems as |tabItem| }}
<div {{action "setSelectedTabItem" tabItem}} >
{{tab-item item=tabItem setSelectedTabItemAction="setSelectedTabItem" }}
</div>
{{/each}}
<div class="item-content">
{{selectedTabItem.content}}
</div>
并将tab-switcher
类文件( app/components/tab-switcher.js
)更改为
export default Ember.Component.extend({
actions: {
setSelectedTabItem: function(tabItem){
this.set('selectedTabItem', tabItem);
}
}
});
此时,如果您在浏览器中查看我们的应用程序,它将正常运行。
但是,这种解决方法不能解决一个事实,即动作只会冒泡到组件的类,所以让我们以一种可行的方式来做。 保留app/components/tab-switcher.js
的更改,但将app/templates/components/tab-switcher.hbs
恢复到先前的状态:
<div class="item-content">
{{selectedTabItem.content}}
</div>
{{#each tabItems as |tabItem| }}
{{tab-item item=tabItem setSelectedTabItemAction="setSelectedTabItem" }}
{{/each}}
现在,将tab-item
模板更改为:
<span {{action "clicked" item }}>{{item.title}}</span>
{{yield}}
然后将tab-item
类文件更改为:
export default Ember.Component.extend({
actions:{
clicked: function(tabItem){
this.sendAction("setSelectedTabItemAction", tabItem);
}
}
});
在这里,您可以看到我们添加了一个动作处理程序来处理对tab-item
标题的单击。 这会将动作从tab-item
组件发送到其父项,即tab-switcher
组件。 该动作将层次结构与参数(即我们单击的tabItem
。 这样可以将其设置为父组件上的当前tab-item
。
请注意,我们正在使用属性setSelectedTabItemAction
作为要发送的动作。 这不是实际发送的操作名称,而是属性中包含的值—在本例中为setSelectedTabItem
,它是父组件的处理程序。
至此,我们结束了对Ember组件的介绍。 我希望你喜欢它。 在整个Ember项目中使用可重复使用的组件所带来的生产力收益不容小((实际上在整个项目中也是如此)。 为什么不试试呢? 本教程的源代码可在GitHub上找到 。
您是否已在Ember中使用组件? 到目前为止,您的经历是什么? 希望收到您的评论。
From: https://www.sitepoint.com/understanding-components-in-ember-2/