33、Ember 组件开发:数据传递与交互实践

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 组件开发的具体流程和相关技术细节。希望这些知识能帮助你在前端开发的道路上不断前进。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值