Ember 组件开发:数据传递与交互实践
1. 组件数据传递基础
在初始阶段,警报组件没有用于渲染内容和类名的状态数据,只有容器。要传递组件状态,可以在
app/templates/application.hbs
中进行操作:
{{flash-alert message="This is the Alert Message" alertType="success"}}
{{outlet}}
</div>
启动服务器,在浏览器中打开
http://localhost:4200/sightings
,就能看到
{{flash-alert}}
组件使用你提供的内联数据进行渲染。
为了动态设置
message
和
alertType
属性,需要一个应用控制器。使用 Ember CLI 生成器添加控制器:
ember g controller application
在
app/controllers/application.js
中添加以下属性:
import Ember from 'ember';
export default Ember.Controller.extend({
alertMessage: null,
alertType: null,
isAlertShowing: false
});
现在可以将控制器属性传递给
app/templates/application.hbs
中的
flash-alert
组件:
</header>
<div class="container">
{{#if isAlertShowing}}
{{flash-alert message=alertMessage alertType=alertType}}
{{/if}}
{{outlet}}
</div>
控制器的属性可以通过动作来设置。应用程序仅在
isAlertShowing
属性设置为
true
且其他属性有值时才渲染组件。这些动作可以来自应用程序的各个控制器,Ember 会自动处理动作冒泡。
2. 路由动作设置
需要在路由中添加一个动作。可以从控制器调用动作,它会依次经过当前控制器、当前路由、父路由,最终到达应用程序路由。
由于
flash-alert
在
app/templates/application.hbs
中,需要创建一个应用程序路由:
ember g route application
在命令行中会出现提示:
[?] Overwrite app/templates/application.hbs?
输入
n
或
no
继续,因为不想覆盖刚刚创建的模板文件,只想添加
app/routes/application.js
文件。
编辑
app/routes/application.js
:
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
flash(data){
this.controller.set('alertMessage', data.message);
this.controller.set('alertType', data.alertType);
this.controller.set('isAlertShowing', true);
}
}
});
3. 触发动作显示警报
现在有了一个动作来设置
flash-alert
显示适当的消息,只需要传递一些数据。数据是一个包含
alertType
和
message
键的对象。
alertType
可以是
"success"
、
"warning"
、
"info"
或
"danger"
。从控制器调用动作的示例如下:
this.send('flash', {alertType: "success", message: "You Did It! Hooray!"});
在创建新的目击记录后添加对应用动作的调用。在
app/routes/sightings/new.js
中添加以下内容:
create() {
var self = this;
this.get('sighting').save().then(function(data){
self.send('flash', {alertType: "success", message: "New sighting."});
self.transitionTo('sightings');
});
点击“New Sighting”按钮创建新的目击记录,选择一个神秘生物和目击者,输入新的位置,然后点击“Save”。一旦目击记录保存到数据库,应用程序会将你路由到目击记录列表,并在列表顶部显示一条新的闪屏消息。
4. 移除警报的操作
最后一步是添加移除警报的动作和事件。只希望在创建新消息后显示
flash-alert
,因此在移除警报时需要将其隐藏。
在
app/controllers/application.js
中添加一个名为
removeAlert
的动作:
export default Ember.Controller.extend({
alertMessage: null,
alertType: null,
isAlertShowing: false,
actions: {
removeAlert(){
this.set('alertMessage', "");
this.set('alertType', "success");
this.set('isAlertShowing', false);
}
}
});
这将把
isAlertShowing
设置为
false
,将
alertMessage
设置为空字符串,并将
alertType
设置为
"success"
。
将
removeAlert
动作发送到组件。在
app/templates/application.hbs
中添加以下内容:
</header>
<div class="container">
{{#if isAlertShowing}}
{{flash-alert message=alertMessage alertType=alertType close=(action "removeAlert")}}
{{/if}}
{{outlet}}
</div>
close=(action "removeAlert")
是 Ember 2.0 中的新语法,称为闭包动作。函数字面量作为名为
close
的属性传递给组件,类似于别名。
在
app/components/flash-alert.js
中调用这个动作:
import Ember from 'ember';
export default Ember.Component.extend({
typeTitle: Ember.computed('alertType', function() {
return Ember.String.capitalize(this.get('alertType'));
}),
click() {
this.get('close')();
}
});
当调用
close
属性时,会触发应用控制器上定义的
removeAlert
动作。通过使用闭包动作,将组件的属性分配给父控制器中定义的函数,并将组件的功能与父控制器的作用域绑定。
操作流程总结
| 步骤 | 操作内容 | 代码示例 |
|---|---|---|
| 1 | 传递组件状态 |
在
app/templates/application.hbs
中添加
{{flash-alert message="This is the Alert Message" alertType="success"}}
|
| 2 | 创建应用控制器 |
ember g controller application
|
| 3 | 添加控制器属性 |
在
app/controllers/application.js
中添加
alertMessage
、
alertType
和
isAlertShowing
|
| 4 | 创建应用路由 |
ember g route application
|
| 5 | 编辑路由动作 |
在
app/routes/application.js
中添加
flash
动作
|
| 6 | 触发动作显示警报 |
在
app/routes/sightings/new.js
中调用
self.send('flash', {alertType: "success", message: "New sighting."})
|
| 7 | 添加移除警报动作 |
在
app/controllers/application.js
中添加
removeAlert
动作
|
| 8 | 发送动作到组件 |
在
app/templates/application.hbs
中添加
close=(action "removeAlert")
|
| 9 | 调用动作 |
在
app/components/flash-alert.js
中调用
this.get('close')()
|
流程图
graph TD;
A[传递组件状态] --> B[创建应用控制器];
B --> C[添加控制器属性];
C --> D[创建应用路由];
D --> E[编辑路由动作];
E --> F[触发动作显示警报];
F --> G[添加移除警报动作];
G --> H[发送动作到组件];
H --> I[调用动作];
5. 挑战任务
青铜挑战:自定义警报消息
触发的
{{flash-alert}}
消息比较通用,可以添加目击记录的位置和日期到消息中。
白银挑战:将导航栏变成组件
将应用模板中的导航栏变成一个组件,添加一个状态属性以显示两种版本的导航,在导航栏组件中添加条件语句以显示特定链接。
黄金挑战:警报数组
重构
flash-alert
组件以接受不同警报类型和消息的警报数组。可能需要同时在屏幕上显示多个警告。使用
Ember.ArrayProxy
代替单独设置警报的属性,添加消息、类型和新的索引属性,以便在点击时从数组中移除该项。
6. 成为优秀前端开发者的建议
6.1 立即编写代码
及时应用所学知识,为项目做出贡献或编写自己的简单应用程序,避免遗忘所学内容。
6.2 持续学习
深入研究感兴趣的内容,编写代码进行实践,阅读相关文档或书籍,还可以收听 JavaScript Jabber 播客了解前端开发的最新动态。
6.3 结识同行
参加本地聚会、在 Twitter 上与前端开发者交流、参加前端会议,扩大人脉。
6.4 探索开源社区
在 GitHub 上探索优秀的前端项目,分享自己的代码,订阅 WDRL 邮件列表了解前端社区的最新情况。
7. 相关技术索引
7.1 HTML 标签与属性
| 标签/属性 | 描述 |
|---|---|
<a>
标签
|
用于创建超链接,通过
href
属性指定链接地址
|
<body>
标签
| 包含网页的可见内容 |
<div>
标签
|
常用作布局容器,可通过
class
属性添加样式
|
<form>
标签
| 用于创建 HTML 表单 |
<h1>
标签
| 表示一级标题 |
<head>
标签
| 包含文档的元数据,如字符编码、页面标题等 |
<hr>
标签
| 用于创建水平分割线 |
<img>
标签
|
用于插入图片,通过
src
属性指定图片地址,
alt
属性提供替代文本
|
<input>
标签
| 用于创建各种表单输入元素,如文本框、复选框、单选框等 |
<label>
标签
|
用于为表单元素定义标签,通过
for
属性关联表单元素的
id
|
<link>
标签
| 用于引入外部资源,如 CSS 文件 |
<meta>
标签
| 用于提供关于 HTML 文档的元数据 |
<option>
标签
| 用于定义下拉列表中的选项 |
<script>
标签
| 用于嵌入或引用 JavaScript 代码 |
<section>
标签
| 用于对文档中的内容进行分节 |
<select>
标签
| 用于创建下拉列表 |
<span>
标签
| 用于内联文本的样式设置 |
<style>
标签
| 用于在 HTML 文档中嵌入 CSS 样式 |
<title>
标签
| 用于定义网页的标题 |
<ul>
标签
| 用于创建无序列表 |
7.2 CSS 相关
7.2.1 选择器
| 选择器类型 | 描述 | 示例 |
|---|---|---|
| 元素选择器 | 选择 HTML 元素 |
p { color: red; }
|
| 类选择器 | 选择具有特定类名的元素 |
.my-class { font-size: 16px; }
|
| ID 选择器 | 选择具有特定 ID 的元素 |
#my-id { background-color: blue; }
|
| 子选择器 | 选择某个元素的直接子元素 |
ul > li { list-style-type: none; }
|
| 后代选择器 | 选择某个元素的所有后代元素 |
div p { margin: 10px; }
|
| 属性选择器 | 选择具有特定属性的元素 |
input[type="text"] { width: 200px; }
|
7.2.2 属性与值
| 属性 | 描述 | 示例值 |
|---|---|---|
color
| 设置文本颜色 |
red
,
#00ff00
,
rgb(255, 0, 0)
|
font-size
| 设置字体大小 |
12px
,
1.5em
,
200%
|
margin
| 设置元素的外边距 |
10px
,
10px 20px
,
10px 20px 30px 40px
|
padding
| 设置元素的内边距 |
5px
,
5px 10px
,
5px 10px 15px 20px
|
display
| 设置元素的显示方式 |
block
,
inline
,
inline-block
,
none
|
position
| 设置元素的定位方式 |
static
,
relative
,
absolute
,
fixed
|
float
| 设置元素的浮动方式 |
left
,
right
,
none
|
clear
| 清除元素的浮动 |
left
,
right
,
both
|
7.3 JavaScript 相关
7.3.1 数据类型
| 数据类型 | 描述 | 示例 |
|---|---|---|
| 基本类型 | ||
Number
| 表示数字 |
10
,
3.14
|
String
| 表示文本 |
"Hello, World!"
|
Boolean
| 表示布尔值 |
true
,
false
|
Null
| 表示空值 |
null
|
Undefined
| 表示未定义的值 |
let x; // x 的值为 undefined
|
| 引用类型 | ||
Object
| 表示对象 |
{ name: "John", age: 30 }
|
Array
| 表示数组 |
[1, 2, 3]
|
Function
| 表示函数 |
function add(a, b) { return a + b; }
|
7.3.2 函数与方法
| 函数/方法 | 描述 | 示例 |
|---|---|---|
addEventListener
| 用于为元素添加事件监听器 |
element.addEventListener('click', function() { console.log('Clicked!'); });
|
console.log
| 用于在控制台输出信息 |
console.log('This is a message.');
|
classList.add
| 用于为元素添加类名 |
element.classList.add('new-class');
|
classList.remove
| 用于移除元素的类名 |
element.classList.remove('old-class');
|
getAttribute
| 用于获取元素的属性值 |
let value = element.getAttribute('data-value');
|
setAttribute
| 用于设置元素的属性值 |
element.setAttribute('data-value', 'new-value');
|
7.4 Ember 相关
7.4.1 组件与助手
| 组件/助手 | 描述 | 示例 |
|---|---|---|
{{#each}}
助手
| 用于遍历数组或对象 |
{{#each items as |item|}} {{item.name}} {{/each}}
|
{{#if}}
助手
| 用于条件渲染 |
{{#if isVisible}} <p>Visible content</p> {{/if}}
|
{{#link-to}}
助手
| 用于创建路由链接 |
{{#link-to 'route-name'}} Link Text {{/link-to}}
|
{{action}}
助手
| 用于触发动作 |
{{action 'myAction'}}
|
{{outlet}}
助手
| 用于渲染子路由的模板 |
{{outlet}}
|
{{x-select}}
组件
| 自定义选择组件 |
{{x-select options=myOptions}}
|
{{yield}}
助手
| 用于在组件中插入内容 |
{{yield}}
|
7.4.2 路由与控制器
| 路由/控制器 | 描述 | 示例 |
|---|---|---|
model
方法
| 用于加载路由的数据 |
model() { return this.store.findAll('post'); }
|
setupController
方法
| 用于设置控制器的属性 |
setupController(controller, model) { controller.set('posts', model); }
|
transitionToRoute
方法
| 用于路由跳转 |
this.transitionToRoute('route-name');
|
send
方法
| 用于触发动作 |
this.send('myAction', data);
|
流程图
graph LR;
A[HTML] --> B[CSS];
A --> C[JavaScript];
C --> D[Ember];
B --> D;
D --> E[组件开发];
D --> F[路由管理];
D --> G[数据交互];
通过以上内容,我们对前端开发中的 HTML、CSS、JavaScript 以及 Ember 框架有了更深入的了解,同时掌握了 Ember 组件开发的具体流程和相关技术细节。希望这些知识能帮助你在前端开发的道路上不断前进。
超级会员免费看
4

被折叠的 条评论
为什么被折叠?



