文章目录
component in Emberjs
1. 什么是 component
一个封装好的可以重复使用的功能单元.一个形象的比喻就是七巧板里面的每一块都是一个组件,每个组件都可以重复使用,通过调节 板的摆放方式(组件属性) 以及 与其他板的组合方式(父子组件的联动) 来实现不同的拼装样式(组件功能).
2. 解决了什么样的问题
在实际生产工作中,会经常遇到需要展示多个 item 的情况,比如 TMIST
项目中的医院列表、APM
项目中的 区域展示列表。在这样的情况下,我们如果使用一个个书写的方式把他们穷举出来,那需要写的就太多了,根据OAOO
(一次且仅一次)的编程原则,我们需要一个这样的解决办法,写一次,来展现医院列表,如果我们提供的灵活性足够,我们可以达到写一次列表组件,展示一类事物的列表。
在 emberjs 中这样的解决思路就是使用 component 。
3. 使用
创建基本组件:
ember g component component-train
可以看到 ember-cli 帮我们生成了两个文件,一个是主管组件展示的template.hbs
,另一个是主管组件逻辑的component.js
。 1
组件的生命周期
任何框架的组件都有其生命周期,而每个框架提供的生命周期钩子不尽相同,但是设计思路是相似的:
这个部分官方文档提供了一些具体钩子的具体使用范例:点击查看。
组件的数据传递
在一个简单的组件中:
{{!-- component-train-passing-properties/template.hbs --}}
<h2>{{title}}</h2>
我们可以在 component.js
中为 title
变量赋值,在 handlebars 文件中将会展示出来:
// component-train-passing-properties/component.js
// ...
this.set('title','welcome to use emberjs');
而在调用组件页面我们将会看到这句话。
但是在实际项目中,我们基本上都是从后端接受数据再通过路由中的handlebars 文件调用组件,将数据传递进去,再进行相应的展示:
{{!-- train/template.hbs --}}
{{component-train-passing-properties title="Welcome to use component!"}}
这个时候,在组件的调用页面,我们就可以看到
展示在我们面前了。
自定义组件属性:
- 修改包裹体的标签:
默认的 组件 外部的包裹元素为div
,我们可以通过使用tagName: 'li'
这种语法来修改包裹体的标签; - 向组件添加 类 名:
有以下几种方法:
- 在定义的时候通过属性添加:classNames: ['header-title']
;
- 在调用的时候通过属性传递:{{component-train-passing-properties class='passing-properties-container'}}
;
- 绑定某一属性,动态添加类:
// component-train-passing-properties/component.js
classNameBindings: ["showBg:show-background"]
而后在对应的 styles.scss
文件内写上样式,这里是添加背景色。
在调用端:
{{!-- train/template.hbs --}}
<section local-class="defined-class">
{{component-train-passing-properties title=title showBg=true}}
{{component-train-passing-properties title=title showBg=false}}
</section>
可以看到:
如果classNameBindings
绑定的属性的值是一个字符串,那字符串将直接传递入组件的类中。
事件调用
在 component.js 文件中,我们可以在内部写一些事件处理逻辑:
actions: {
changeText(text) {
this.set('text',text + ' !')
}
}
总结
上面就是 emberjs 中 component 的一些基础用法,包含 组件创建/数据传递/动态样式 等。在实际的项目中,我们需要从设计原图开始一步步做,这个时候就需要我们拆分页面,将可复用的部分拆分成一个个组件,然后再通过组件的相互嵌套完成一个个页面的拼装。
4. 拆分组件
这个问题呢,是一个比较偏经验性的问题,比较考验编程人员的抽象能力,这方面我做的就不是很好,但是我刚好从高人那里学到了几招,就在这里班门弄斧一下。
数据结构与组件
拿到设计图之后我们在充分了解了整个项目抑或是单个页面之后,我们需要考虑的是 页面结构,随之而来的一个问题是数据结构,这是不分家的,你期望你的页面数据是如何展示的,你的数据结构就应该辅助你,或者数据结构是这样的,那你的页面结构也应该相应的这么做。在之前杨总告诉我们要开始做的 ERD 图 也可以再设计ERD图的同时思考一下页面的结构。虽不尽相同,但思想一致。
自己的做法
在我们项目前期,我们不可能把一个组件抽离的完美,或者拆分页面结构非常清晰完整。也就是不要过早的过度拆分组件。我们也可以在一个route中将一个页面全写出来,在写的过程中我们就可以根据严谨的 html 结构 以及业务需求来了解到一个组件如何拆分。这样做的前提就是写出来的 html 结构必须清晰。
在拆分的过程中,我们肯定会考虑到组件的复用与灵活性。这个可以考虑使用 yield
反出一些数据或可定制的子组件使调用者更加灵活。
是将数组传入组件还是将item传入组件
这是我做组件过程中思考过的一个问题,就是在像 药品列表 这样的样式中。两种数据传入是会产生不同的影响的。
总结
这个拆分组件过程写的比较浅显,更多的需要在项目中不断的思考。
其他 Service
在实际的项目中,我们通常会遇到相同或者相似的处理逻辑,如果每次都在component/controller/route中写一遍,或者靠 ctrl+c/ctrl+v
来完成,那就不符合我们上面提到的OAOO
的编程原则。
创建service
ember g service change
ember cli就会自动帮我们生成一个service.js 文件:
import Service from "@ember/service";
export default Service.extend({
changed(text) {
return text + " changed!";
}
});
注入到需要使用到的地方
可以注入到 route/controller/component 中,目前以 component 为例:
import Component from "@ember/component";
import { inject as service } from "@ember/service";
export default Component.extend({
// 注入方式一
change: service(),
// 注入方式二
mut: service("change"),
});
注入之后的 service 既可以在 js 文件中使用,亦可以在 handlebars 文件中使用。
文档中一些使用 service 的示例为:
- User/session authentication.
- Geolocation.
- WebSockets.
- Server-sent events or notifications.
- Server-backed API calls that may not fit Ember Data.
- Third-party APIs.
- Logging.
总结
本文写的比较仓促,肯定存在错误,一些高级用法也没有解释的清楚,实际项目中的应用也未能举例说明,在之后的时间里会不断更新。
Written by Frank Wang.
有问题可以下方评论,或发邮件至 法研鲁迅 .
在使用原生的目录结构时,生成的文件名称可能有所不同;另外 组件的名称也必须有中划线。 ↩︎