在这一课中,我们将重点讨论如何通过规则和操作来实现组件的行为。
我们已经了解到,在创建自己的组件时,您将编写由一个表达式和一个或多个操作组成的规则。如果表达式为真,则将执行操作。
规则
规则由三个要素组成:
- ID:在作用域内必须是唯一的规则标识符
- 表达式:触发此规则的条件
- 操作:触发该规则时执行的操作的引用或定义
一条规则也总是被分配给一个状态:
国家
<onenter>:
这是进入一个步骤时的第一个状态。在这种状态下,用户界面不可用,因此不能使用与用户界面相关的操作。不过,如果你想初始化参数,将其用于用户界面映射,那么这是正确的状态。<onresume>(继续):
<onenter> 之后的第二个状态。在此状态下,用户界面可用,您可以使用用户界面更新操作修改已加载的布局。<onpause>
和<onleave>:
只要使用step_transition
或finish_workflow
操作离开当前步骤或整个组件,就会出现这些状态。由于转换不可中断,因此不能在此使用使用这些操作的规则。在onpause
状态下,步骤的资源仍然存在,而在 onleave
状态下则
不存在。<onevent>:
这可能是最重要的状态。每次处理事件时,都会检查此状态下定义的规则。与用户交互相关的所有规则都在此状态中定义。
一个状态中的规则以任意顺序进行评估,因此一条规则的表达不应取决于在它之前检查的另一条规则。
另一方面,规则中的操作会按照您写下的顺序执行。
评估/执行顺序:
表达
表达式的一般结构由操作数(如上下文变量)和运算符(如"="或">")组成,就像任何编程语言一样。
支持的运算符:+, -, &&, ||, !, /, ==, >, >=, <, <=, %, *, !=
让我们看看 "分页文本 "组件中的另一个简单示例,它可以在多个页面上显示任意长度的文本:
<onevent>
<rule id="next_page">
<expression><![CDATA[
#{event:command} == 'NEXT_PAGE' && #{page} < #{numberofpages}
]]></expression>
<actions>
<action ref="next"/>
<action ref="settext"/>
</actions>
</rule>
</onevent>
技巧和窍门
- 除非用单引号将空格标记为字符串,否则表达式中的空格将被删除。
- 当按下
名称为 "NEXT_PAGE "
的按钮,且当前页不是最后一页时,此表达式为真。 - 您可能已经注意到表达式周围的
<![CDATA[ ... ]]>
标记。在这种情况下,该标记是必需的。它是一个 XML 关键字,用于告知解析器后面的内容不是标记。如果没有<![CDATA[ ...]]>
标记,这个表达式将使我们组件的 XML 无效,因为它包含了 XML 保留字符&
和<。
- 在所有表达式中添加
<![CDATA[ ... ]]>
标记。这样就不必考虑是否使用了 XML 保留字符。
活动
当您的规则处于步骤的<onevent>
状态时,您可以对事件做出反应,并在表达式中使用事件的属性。事件的结构如下
{
"command": "...",
"device":
{
"modality": "...",
"name": "...",
"source": "...",
"descriptor": "..."
},
"payload":
{
"...": "...",
"error": "..."
}
}
您只需要这些字段的子集:
1. 命令: 该事件的命令,如 "NEXT"。例如,该命令可以与组件布局或工作流程描述中的 ID 相对应。例如#{event:command} == 'CANCEL' (取消
2. 设备: 事件的来源。可使用简短符号访问该字段。
表达式 #{event(SPEECH):command=='NEXT"等价于表达式#{event:device.modality} =='SPEECH' && #{event:command} =='NEXT' 。模式取决于事件发射器。例如,#{event:device.modality} == 'MENU_SELECTION' (菜单选择
3. 有效载荷: 有效载荷的结构/字段取决于触发事件的操作/处理程序。例如,#{event:payload.amount}(事件:payload.金额
payload.error : 包含错误信息(如果有的话)。例如,#{event:payload.error}(事件:payload.error
您可以限制事件源,确保只有在特定输入模式引起事件时才会触发规则。例如,您可以使用语音命令 "NEXT",让工人确认他们已经完成了某项任务或产品的工作。他们也可以使用一个设备,用 "NEXT "命令触发事件。当按下硬件按钮时,屏幕上的可用选项会随之旋转。您不想在使用硬件按钮时激活该规则,因此需要指定模式:#{event(SPEECH):command} == 'NEXT'。
一般事件源(模式):语音、手势、键盘、条形码、hw_keys、相机图片、菜单选择、媒体输入
实例
让我们来看看一些比较常见的规则结构:
启动和拆除
我们的第一个示例是一个典型的用例:在进入或离开组件时自动执行操作。
提示和技巧:某些规则需要无条件执行。为此,可以将表达式设置为<expression>1</expression>。
<onresume>
<rule id="init">
<expression>1</expression>
<actions>
<action ref="reset_counter"/>
</actions>
</rule>
</onresume>
按顺序执行规则
一个状态中的规则以任意顺序进行评估。在某些情况下,需要在同一步骤内按顺序执行规则。为此,可以使用定时器按顺序触发规则。定时器操作通过用户定义的命令手动触发事件。
作为第一条规则的最后一个操作,您将添加一个计时器操作。然后就可以在第二条规则的表达式中添加用户定义的命令。
<onevent>
<rule id="first_rule">
<expression><![CDATA[ #{event:command}=='VALID' ]]></expression>
<actions>
<action ref="do_something"/>
<setvar id="increment_counter">
<context_of>workflow</context_of>
<context_update>
<param name="counter" type="long">#{counter} + 1</param>
</context_update>
</setvar>
<timer id="check_counter_trigger" command="CHECK_COUNTER" delay="0"/>
</actions>
</rule>
<rule id="second_rule">
<expression><![CDATA[ #{event:command}=='CHECK_COUNTER' && #{counter} >= #{max_iterations} ]]></expression>
<actions>
<finish_workflow id="exit"/>
</actions>
</rule>
</onevent>
任务
让我们行动起来吧
作业 1:
在我们的 "选择 "组件中,我们一直没有使用<![CDATA[ ... ]]>
标记,以便让初学者尽可能简单地使用该组件。作为最佳实践,我们建议在所有表达式中使用该标记,以消除潜在的错误源。
- 在现有规则中添加
<![CDATA[ ... ]]>
标记。
作业 2:
让我们确保用户确定他们的选择。例如,如果我们一选择 "苹果",苹果派就开始生产,我们可能会希望用户再次确认:
- 阅读有关 ui_dialog操作的内容
- 在组件中添加一个对话框,显示所选值并要求用户确认选择。
下载工作流程(作业前)
帮助和资源
- 对于作业 2,您必须创建一条新规则,对
ui_dialog
选项的<command>
作出反应。现有规则的部分逻辑必须转移到新规则中。
解决方案
下载组件(作业后)
至此,第四课已经结束。在第五课中,我们将探讨仅使用 XML 定义工作流的一些局限性,以及如何在工作流中使用 JavaScript 来解决这些问题。