学习目标
- 为您的应用定义自定义事件。
- 从组件控制器创建和激发事件。
- 创建动作处理程序来捕获和处理其他组件发送的事件。
- 将一个大的组件重构成更小的组件。
连接组件与事件
组成和分解
如果您以源代码的形式看看我们的小费用应用程序,并列出单独的代码工件,您将得到如下内容。
- expenses component
- expenses.cmp
- expensesController.js
- expensesHelper.js
- expensesList component
- expensesList.cmp
- expenseItem component
- expenseItem.cmp
- ExpensesController (server-side)
- ExpensesController.apex
以下是所有内容如何组合在一起的情况,以及稍后您接线的createExpense和updateExpense事件。
但是,如果你看屏幕上的应用程序,你看到了什么?你应该看到什么,你看到的最终会看到什么,是应用程序分解成更多的组件。您会看到,您可以将我们的应用程序进一步分解为更小的碎片,比迄今为止所做的更多。至少,我们希望您看到“添加费用”表单实际上应该是它自己的独立组件。 (这就是为什么我们在用户界面上画一个盒子的原因!)
为什么我们不把这个表格作为一个单独的组件?不这样做是迄今为止我们在这个模块的过程中最大的捷径。在软件设计方面,这比我们称之为“恶心”的黑客更糟。构建Lightning组件应用程序的正确方法是创建独立的组件,然后将它们组合在一起以构建新的更高级别的功能。为什么我们不采取这种方法?
我们采取了快捷方式,因为它将主要费用数组组件属性和影响它的控制器代码保存在同一个组件中,所以我们在“主费用”组件中保留了“添加费用”表单。我们希望createExpense()辅助函数能够直接触碰费用数组。如果我们将“添加费用”表单移到单独的组件中,那是不可能的。
为什么不?我们很早就介绍了这个原因,但是现在我们想要真正的琢磨一下。闪电组件应该是独立的。它们是封装所有基本功能的独立元素。一个组件不允许触及另一个组件,甚至是一个子组件,并且改变它的内部组件。
有两种主要的方式与另一个组件进行交互或影响其他组件。第一种方法就是我们已经看到并做了相当多的工作:在组件的标签上设置属性。组件的公共属性构成了其API的一部分。
与组件交互的第二种方式是通过事件。与属性一样,组件声明它们发出的事件以及它们可以处理的事件。和属性一样,这些公共事件构成了组件的公共API的一部分。我们实际上已经使用和处理了事件,但事件隐藏在一些便利功能之后。在这个单元中,我们将把事件拖入光明中,并创建一些我们自己的事物。
布线电路隐喻再次
您可以将属性和事件之间的区别视为有线电路和无线电路之间的区别。我们在这里不是说无线电话。一个组件不能获得另一个组件的“编号”并调用它。那将是一个属性。不,事件就像无线广播。你的组件到达收音机,并发出一条消息。有没有人打开收音机,并调整到正确的频率?你的组件没有办法知道 - 所以你应该以这样的方式编写你的组件,如果没有人听到他们广播的事件。 (也就是说,事情可能不起作用,但什么都不应该崩溃。)
从组件发送事件
好的,足够的理论,让我们做一些特定的应用程序,看看事件如何在代码中工作。我们将开始实施报销?复选框。然后,我们将采取我们所学到的,并用它来重构“添加费用”表格到自己的组件,这是伟大的工程师的意图。
首先,我们将重点放在Reimbursed__c字段的<lightning:input>上的点击处理程序。
<lightning:input type="toggle"
label="Reimbursed?"
name="reimbursed"
class="slds-p-around--small"
checked="{!v.expense.Reimbursed__c}"
messageToggleActive="Yes"
messageToggleInactive="No"
onchange="{!c.clickReimbursed}"/>
- 获取已更改的费用项目。
- 创建一个服务器操作来更新基础费用记录。
- 将费用计入行动。
- 设置一个回调来处理响应。
- 触发操作,将请求发送到服务器。
- 当响应到来并且回调运行时,更新费用属性。
({
clickReimbursed: function(component, event, helper) {
var expense = component.get("v.expense");
var updateEvent = component.getEvent("updateExpense");
updateEvent.setParams({ "expense": expense });
updateEvent.fire();
}
})
- 获取更改的费用。
- 创建一个名为updateExpense的事件。
- 将费用打包到事件中。
- Fires 事件。
定义一个事件
我们要做的第一件事是定义我们的自定义事件。在开发者控制台中,选择 , 并将事件命名为“updateEvent”。用下面的标记替换默认的内容。
<aura:event type="COMPONENT">
<aura:attribute name="expense" type="Expense__c"/>
</aura:event>
发送事件
我们已经看过如何在clickReimbursed操作处理程序中实际触发一个事件。但是要做到这一点,我们需要做最后一件事,那就是注册事件。将这一行标记添加到费用项组件,正好在其属性定义下方。
<aura:registerEvent name="updateExpense" type="c:expensesItemUpdate"/>
- 通过创建闪电事件定义自定义事件,给它一个名称和属性。
- 注册您的组件发送这些事件,通过选择一个自定义事件类型,并给这种类型的具体使用一个名称。
- 通过以下方式在控制器(或助手)代码中触发事件:
- 使用component.getEvent()来创建特定的事件实例。
- 用fire()发送事件。
如果你继续执行所有我们刚刚看过的代码,你可以测试一下。重新加载您的应用程序,并切换报销?复选框几次。如果你错过了一步,你会得到一个错误,你应该重新检查你的工作。如果你做的一切正确...嘿,等等,花费改变颜色显示其报销?状态,就像预期的一样!
这个行为在我们开始这个单位之前就已经存在了。这就是<lightning:input>组件具有value =“{!v.expense.Reimbursed__c}”集合的效果。切换开关时,费用的本地版本将更新。但是这个改变没有被发送到服务器。如果您查看Salesforce中的费用记录,或重新加载应用程序,则不会看到更改。 为什么不?我们只做了一半的工作来为我们的活动创建一个完整的电路。我们必须通过在另一端创建事件处理程序来完成电路布线。该事件处理程序将负责将更改发送到服务器,并使更新持久。处理事件
使费用项组件发送一个事件需要三个步骤。启用费用组件来接收和处理这些事件需要三个并行的步骤。
- 定义一个自定义事件。我们已经做到了这一点,因为费用项目正在发送费用正在接收的相同的自定义事件。
- 注册组件来处理事件。这将事件映射到动作处理程序。
- 实际上在动作处理程序中处理事件。
由于我们已经完成了第一步,我们立即转到第二步,注册费用来接收和处理updateExpense事件。就像注册发送一个事件一样,注册来处理一个事件是一行标记,你应该在init处理程序之后添加到费用组件中。
<aura:handler name="updateExpense" event="c:expensesItemUpdate"
action="{!c.handleUpdateExpense}"/>
handleUpdateExpense: function(component, event, helper) {
var updatedExp = event.getParam("expense");
helper.updateExpense(component, updatedExp);
}
updateExpense: function(component, expense) {
var action = component.get("c.saveExpense");
action.setParams({
"expense": expense
});
action.setCallback(this, function(response){
var state = response.getState();
if (state === "SUCCESS") {
// do nothing!
}
});
$A.enqueueAction(action);
},
重构帮助函数
让我们回到我们看到的那个机会来分解一些常见的代码。除了回调之外,这两个辅助函数是相同的。所以,我们来创建一个新的,更广义的函数,将回调作为参数。
saveExpense: function(component, expense, callback) {
var action = component.get("c.saveExpense");
action.setParams({
"expense": expense
});
if (callback) {
action.setCallback(this, callback);
}
$A.enqueueAction(action);
},
createExpense: function(component, expense) {
this.saveExpense(component, expense, function(response){
var state = response.getState();
if (state === "SUCCESS") {
var expenses = component.get("v.expenses");
expenses.push(response.getReturnValue());
component.set("v.expenses", expenses);
}
});
},
updateExpense: function(component, expense) {
this.saveExpense(component, expense);
},
重构添加费用表单
<!-- 新的费用表格 -->
<lightning:layout >
<lightning:layoutItem padding="around-small" size="6">
<c:expenseForm/>
</lightning:layoutItem>
</lightning:layout>
createExpense: function(component, newExpense) {
var createEvent = component.getEvent("createExpense");
createEvent.setParams({ "expense": newExpense });
createEvent.fire();
},
<aura:registerEvent name="createExpense" type="c:expensesItemUpdate"/>
<aura:handler name="createExpense" event="c:expensesItemUpdate"
action="{!c.handleCreateExpense}"/>
handleCreateExpense: function(component, event, helper) {
var newExpense = event.getParam("expense");
helper.createExpense(component, newExpense);
},
奖金课初级视觉改进

如果它也困扰着你,那么这里是如何解决它的。 (我们一直这样做直到我们将表单重构为自己的组件)。在费用项目组件中,通过单击STYLE按钮添加一个样式资源。用下面的代码替换默认的样式规则。
.THIS.slds-theme_success .slds-form-element__label {
color: #ffffff;
}
.THIS.slds-theme_success .slds-text-title {
color: #ffffff;
}
最后,我们想通过添加一些容器组件来改进我们的应用程序的布局。最后一点也让您有机会在所有的变化之后看到完整的费用部分。在费用组件中,将费用列表标记替换为以下内容。
<lightning:layout>
<lightning:layoutItem padding="around-small" size="6">
<c:expensesList expenses="{!v.expenses}"/>
</lightning:layoutItem>
<lightning:layoutItem padding="around-small" size="6">
Put something cool here
</lightning:layoutItem>
</lightning:layout>