Lightning-组件(5)操作

学习目标

完成本单元后,您将能够:

  • 创建一个客户端控制器来处理用户操作。
  • 从组件属性读取值。
  • 从组件中的用户界面控件读取值。
  • 用JavaScript编写控制器代码来改变用户界面。

处理与控制器的行动

到目前为止,我们只使用XML风格的标记。到目前为止,让组件的输出更改的唯一方法是更改​​该标记。到目前为止,我们的组件没有对用户输入做出反应。到目前为止,我们还没有编写任何JavaScript。

这个单位的所有变化。

为了开始,我们来看一个非常简单的组件,想象一下为了处理它的简单行为需要做些什么。

Message of the day: You look nice today button, Today is going to be a great day button

这是helloMessageInteractive,很难想象一个简单的组件“做些什么”。它是一些静态文本,一个(当前空白)消息和两个按钮。代码如下:

<aura:component>
 
    <aura:attribute name="message" type="String"/>
 
    <p>Message of the day: {!v.message}</p>
 
    <div>
        <lightning:button label="You look nice today."
            onclick="{!c.handleClick}"/>
 
        <lightning:button label="Today is going to be a great day!"
            onclick="{!c.handleClick}"/>
    </div>
 
</aura:component>

这应该看起来很熟悉。我们真正做的是将两个<lightning:button>组件添加到helloMessage。当你点击一个按钮,当天的消息被更新。

那么,还不完全。如果您已经输入了代码并自己尝试过,那么您已经注意到,当您单击其中一个按钮时,您会收到错误消息。

There is a problem

我们将首先承认,并不是每一个你会在Lightning Components中看到的错误信息都像你所希望的那样有帮助。但是这个是!它说没有名为“handleClick”的控制器操作。 “handleClick”从哪里来?它来自我们分配给两个<lightning:button>标签中每一个的onclick属性的表达式:

onclick="{!c.handleClick}"

鉴于这是一个按钮,你可能会猜测onclick属性是如何为点击按钮分配一个行为。但是我们分配了什么?表达式{!c.handleClick},可能有点神秘。

这其实很简单。就像前面的v.message表达式一样,c.handleClick是一个值提供者c,带有一个属性handleClick。 c是组件客户端控制器的值提供者,handleClick是在该控制器中定义的函数。所以,{!c.handleClick}是对组件控制器中的一个动作处理器的引用。

c.handleClick: c is a value provider for the component controller, with the property handleClick, a function defined in that controller

Uh, 什么是控制器?

哎呦!控制器基本上是一组代码,用于定义应用程序在“事情发生”时的行为,其中“事物”是指用户输入,定时器和其他事件,数据更新等等。如果你在任何数量的开发者网站上查找“模型 – 视图 – 控制器”,你会得到不同的定义。就我们的目的而言,对于Lightning组件,控制器是组件包中的一个资源,该组件包含该组件的操作处理程序。而动作处理程序只是具有特定功能签名的JavaScript函数。

超越基础

我们在这个单元中谈了很多关于控制器的知识,而且我们知道这个组件本身就是一个视图。我们甚至提到了MVC或模型 – 视图 – 控制器的设计模式,这在Web应用程序框架中很常见。闪电组件建立在MVC模式上吗?

总之,没有。可以肯定的是有相似之处,但是说Lightning组件是View-Controller-Controller-Model或者View-Controller-Controller-Database可能更为正确。

为什么“控制器”在这个模式名称翻倍?因为在与Salesforce交互时,除了我们在本单元中使用的客户端控制器外,您的组件还将拥有服务器端控制器。这个双控制器设计是Lightning组件和MVC之间的主要区别。

“模型”和“数据库”有什么区别?在传统的MVC中,模型是底层数据存储(通常是关系数据库)和其他应用程序之间的程序化抽象(通常是一个类)。在Lightning组件中,没有Apex类直接位于@AuraEnabled控制器方法和DML操作之间。但是再一次,sObjects已经是您的Apex代码和底层存储层之间的抽象了。您可以添加计算字段,验证逻辑,甚至以触发器的形式添加完全的编程行为。那么,这是一个数据库还是一个模型?我们说po-TAY-tow,但是如果你想用po-TAH-tow去,那真是太酷了。

困惑?激动吗?我们将在后面的单元中对服务器端控制器的细节进行分类。

让我们更详细地看看helloMessageInteractive控制器,并解释更具体一些。

({
    handleClick: function(component, event, helper) {
        var btnClicked = event.getSource();         // the button
        var btnMessage = btnClicked.get("v.label"); // the button's label
        component.set("v.message", btnMessage);     // update our message
    }
})
控制器资源有一个有趣的格式。它们是包含名称 – 值对映射的JavaScript对象,其中名称是操作处理程序的名称,值是函数定义。


行动处理程序

名称 – 值对和特定函数签名的组合是一个动作处理程序。您将会听到或看到交替使用的术语“动作处理程序”,“控制器动作”和“控制器功能”,而且大部分都是正确的。他们几乎总是提到同样的事情。 (我们不会担心这个模块中的异常。)

不要太担心控制器资源的特殊格式。当您在开发者控制台中点击CONTROLLER按钮时,您将获得一个已添加示例操作处理程序的控制器资源。一个技巧是 – 如果你忘记了,你会得到语法错误 – 你需要在操作处理程序之间加逗号。这只是基本的JavaScript语法,我们稍后会看到具体细节。

实际的handleClick函数只有四行代码,但起初似乎很难理解。在高层次上,这很简单:点击按钮时,其操作处理程序被调用(1)。在动作处理程序中,控制器获取被单击的按钮,将标签文本从中拉出,然后将组件的消息属性设置为该文本(2)。并且当天的消息被更新(3)。你今天看起来不错!

In the action handler, the controller gets the clicked button text, then sets the component message attribute

很简单,对吧?好…

因为这是非常重要的,让我们逐行分解。

handleClick: function(component, event, helper) {

操作处理程序名称,后跟一个匿名函数声明。这里重要的是函数签名。虽然这不是技术上的要求,但您应该始终声明您的控制器功能采取这三个参数。现在我们将更多地讨论它们,但是现在这些参数代表:

  • component—组件。在这种情况下,它是helloMessageInteractive。
  • event—导致操作处理程序被调用的事件。
  • helper—组件的助手,另一个可重用函数的JavaScript资源。
    var btnClicked = event.getSource();         // the button
请记住,handleClick已连接到我们的<lightning:button>标记及其onclick属性。那么,事件就是有人点击按钮。在这个事件里面,它有一个源的概念,即产生事件的东西,也就是按钮本身。所以,调用event.getSource()让我们引用被点击的特定<lightning:button>。
    var btnMessage = btnClicked.get("v.label"); // the button's label

我们现在做什么,我们有一个参考按钮?我们在里面查看它的标签,它在组件标记中的<lightning:button>上设置。例如,<lightning:button label =“今天看起来不错。” …>。

让我们再想一想。我们没有在我们面前定义<lightning:button>,但标签只是另一个属性,非常类似于我们添加到helloMessageInteractive的消息属性。您可以在任何组件上调用get(),并以v.attributeName的格式提供您想要检索的属性的名称。结果是属性值。

请注意,就像在组件标记中一样,v代表视图,组件本身 – 但在这种情况下,它是<lightning:button>子组件,而不是helloMessageInteractive!想想这样。 btnClicked.get(“v.label”)在任何组件btnClicked的肩膀上点击并且说“嘿,给我v.label”。该组件认为“v就是我”,在自己的内部查找,并返回其标签属性的值。

所以,现在我们有一个从按钮中检索的文本字符串,我们只剩下一步:将我们的消息属性更改为新的消息文本。毫不奇怪,就像get()从组件中读取值一样,set()写入一个值。

    component.set("v.message", btnMessage);     // update our message
但是,让我们注意一个重要的区别。我们在btnClicked上调用了get(),这是helloMessageInteractive中的<lightning:button>。我们在组件上调用set() – helloMessageInteractive组件本身。实际上,您将在每个创建的组件中重复这种模式:从子组件获取值,可能会进行一些处理,并在组件中设置值。


闪电组件视图 – 控制器编程模型

好的,检查一下时间。这是有道理的吗?当然?如果你这么想,确保你已经使用前面的代码创建了helloMessageInteractive组件。它是一个组件,复制/粘贴代码需要两分钟的时间,但能够使用它是理解处理操作的关键。

你在这里做的事情看起来很简单,因为它不是很多代码行。但是这些代码行说明了使用Lightning组件构建应用程序的一些基本概念。

您可以将组件连接到动作处理程序上,将它们连接起来。将helloMessageInteractive想象成一个简单的电路。有开关,还有灯泡。 (Lightning组件框架提供电源。)本身,一个开关可能会发出一个很好的咔哒声,但是直到你连接它,它不是功能。你可以有最时尚的爱迪生风格的灯泡,但直到你把它连接起来,它不会照亮任何东西。

Lightning组件也是如此。就在前面,我们说组件捆绑中的不同资源是相互“自动连接”的。这是真的:接线采取v和c值提供商的形式。它们会自动创建并在您的组件中可用,因此您的控制器可以引用组件,反之亦然。但是这个自动接线只发生在组件.cmp资源和控制器.js资源之间的高层次 – helloMessageInteractive中。这是下图中的绿色箭头。

helloMessageInteractive and its controller are auto-wired

将一个特定的<lightning:button>组件连接到一个特定的动作处理程序 – 也就是将产生事件的东西(比如按钮)连接到处理事件的东西,比如一个特定的控制器功能 – 这是你需要的连线自己做。其实,你只是做了你自己!这些是完成工作电路所需的红色箭头。

将{!c.handleClick}添加到<lightning:button>组件(1)的onclick属性,将其连接到特定的操作处理程序。调用component.set(“v.message”,newMessage)(2)将该操作处理程序的结果连接到组件的消息属性。它本身连接到{!v.message}表达式。

您可以进一步将onclick事件视为沿着您创建的电路流动的电子。如果你还没有创建一个完整的电路,事件不会发生,没有任何反应。当你开始编写自己的组件时,记住这一点。你有一个完整的电路?你确定?如果有疑问,有时候可以在白板或纸上画出全部草图,并确认每个连接。

你会把组件,事件和处理程序连接在一起,所以你经常会感觉像电工。 (或者,考虑到框架的名字,也许是本·富兰克林。)把事情联系在一起是Lightning组件的基本编程模型。

所以,我们再做一些。毕竟,练习是完美的。

函数链接,重新布线和简单调试

我们的handleClick的第一个版本是三行代码,因为我们将get-process-set模式中的每一步分解成单独的行。你可以使用一些叫做函数链的东西把它们折成较少的行。由于您可能会在其他Lightning组件代码中看到这一点,因此我们可以让它自己旋转。在handleClick之后,将以下附加代码添加到helloMessageInteractive控制器中。

    handleClick2: function(component, event, helper) {
        var newMessage = event.getSource().get("v.label");
        component.set("v.message", newMessage);
    },

    handleClick3: function(component, event, helper) {
        component.set("v.message", event.getSource().get("v.label"));
    }

Whoopsie!尝试保存时是否出现语法错误?当我们说你需要在你的动作处理程序之间添加逗号的时候,记得早些时候?这是这个问题。在handleClick的最后一个大括号(“}”)后面添加一个逗号,就像你在前面的代码片段的handleClick2的末尾可以看到的那样。

这些动作处理程序与handleClick完全相同,使用更少的代码行。他们通过跳过中间变量来做到这一点,通常通过直接将“链接”链接到下一个函数调用,通过将该调用添加到前一个函数调用的结尾,以句点分隔。 (在查看handleClick和handleClick2之间的差异时,这个概念是最清楚的。)

你喜欢哪种风格是个人品味的问题,也许你的组织的编码风格。你的卑微的作者喜欢handleClick2,分离得到和设置,但不打扰与按钮的变量,我们只需要它的标签文本。

当然,通过将onclick属性设置为{!c.handleClick2}或{!c.handleClick3},您无法验证新的动作处理程序是否正常工作,直到连线<lightning:button>才能使用其中的一个。把它看作是从一个灯泡断开电线,然后把它们连接到另一个灯泡。就这么简单!

在这一点上,你重新加载应用程序,点击一个重新布线的按钮,…呃,这是相同的设计,不是吗?我们甚至可以告诉哪个动作处理程序被调用?

有时候简单是最好的。让我们添加一些记录到一个动作处理函数:

    handleClick2: function(component, event, helper) {
        var newMessage = event.getSource().get("v.label");
        console.log("handleClick2: Message: " + newMessage);
        component.set("v.message", newMessage);
    },

现在,如果连接一个<lightning:button>来处理Click2,则只要您点击它,您就会在浏览器的JavaScript控制台中看到一条日志消息。

是的,有更复杂的调试工具,但打印到控制台的东西是一个悠久的调试技术。如果要输出某种类型的对象,请使用JSON.stringify(yourObject)将其包装,以获取更多有用的细节。当你快速浏览时,console.log()是你的朋友。

我们不会在这里介绍更复杂的调试工具和技术,但请参阅参考资料中的一些精彩的工具和说明。

好的,helloMessageInteractive很简单,并且有一个硬编码(和无情的积极)的态度。在下一个单元中,我们将处理更复杂的事情,并学习如何捕捉真实的用户输入。而且,由于现实世界中的人们并不总是如此积极,我们也将学习如何验证他们的输入。