至此,我们已经有了一个非常漂亮的组件。但是,如果我们想把它传递给其他人(尤其是非开发人员),它的实用性就非常有限了。它只能提供苹果和梨之间的选择。虽然这对我们的第一个客户(可能是一家水果蛋糕工厂)来说非常完美,但我们接下来要服务的汽车公司可能不会使用增强现实技术来帮助工人在休息室选择水果。是时候让我们的组件更具可重用性和可配置性了。
你已经知道如何配置组件了。点击组件时,侧边栏会弹出配置选项。使组件可配置包括两个部分:定义用户可配置的内容和处理所选值。
定义配置选项
要提供的配置选项以 JSON 格式定义。用户可以选择一系列输入类型,如简单文本输入、复选框输入和文件上传输入。
下面是一个配置示例。
{
"tab1": {
"title_text": {
"title": "Title",
"inputType": "textinput",
"value": "Please select"
}
},
"tab2": {
"options": {
"title": "Options",
"inputType": "map-input",
"placeholder": {
"key": "Option Key",
"value": "Option Title"
},
"value": [
{
"key": "option1",
"value": "Option 1"
},
{
"key": "option2",
"value": "Option 2"
},
{
"key": "option3",
"value": "Option 3"
}
]
},
"use_all": {
"title": "Offer last option",
"inputType": "checkbox-input",
"value": "true"
}
}
}
JSON 文件根层级的对象是配置面板的选项卡(其键将显示为选项卡的标题)。每个输入字段对象至少有三个属性:
标题
,即显示在配置面板输入框上方的标题inputType
是您希望显示的输入字段类型值
:即用户在输入字段中输入的内容(或默认值)
您还可以添加info
属性,它将以工具提示的形式呈现,可用于更详细地解释输入字段的用途。
此外,根据所使用的输入类型,还有许多特定属性。
有一些高级技术可以改进配置面板的用户界面。例如,可以将多个输入字段组合到可重复、可折叠的容器中,或仅有条件地显示某些输入字段。这些将在下面的示例中展示。
处理选定的数值
定义好配置后,就可以将配置值嵌入到组件中了。您可以使用§{
... }§ 访问配置文件值。}§.
在括号内,可以使用点号来访问配置对象。在预编译步骤中,这些占位符将被配置值替换。
例如,您可以创建一个映射,将我们在上例中定义的 "标题 "值包含在步骤布局中,就像这样:
<mapping>
<ui_element name="Topic">
<param name="content">§{ tab1.title_text.value }§</param>
</ui_element>
</mapping>
提示和技巧:访问配置时的一个典型错误是忘记了结尾的".value"。
您还可以使用辅助函数来实现配置。这些函数可以帮你做很多事情,比如
- 执行仅根据配置有条件地添加到工作流中的规则
- 循环查看配置值,并为每个值创建规则/操作/...
- 处理配置值,以便进一步处理
我们也来看一个使用辅助程序的例子:
§{#each tab2.options.value}§
§{#unless @last}§
<rule id="opt_§{key}§">
<expression><![CDATA[ #{event:command} == '§{value}§' ]]></expression>
<actions>
<action ref="set_command"/>
</actions>
</rule>
§{/unless}§
§{#if @last}§
§{#if (and tab2.use_all.value (compare (collection tab2.options.value "size") ">" 1))}§
<rule id="special_opt_§{key}§">
<expression><![CDATA[ #{event:command} == '§{value}§' ]]></expression>
<actions>
<action ref="special_action"/>
</actions>
</rule>
§{/if}§
§{/if}§
§{/each}§
这里有几个要点需要注意:
- 辅助函数前面的
#
是必需的,它表示该函数包围并引用了一个代码块。 - 您可以嵌套辅助函数,并从内向外对它们进行评估。在本例中,
集合
辅助函数返回的大小为 3,然后与 1比较
,结果为 true。在对这一结果和复选框输入值应用 "逻辑和 "后,我们得到了 if-helper 函数的最终布尔值。 - 在一些块帮助程序中,有一些自动设置的变量,可以帮助你管理数据数组/映射中的位置。这些变量是
@first
、@last
、@index
和@key
。
使用上述示例配置进行预编译后,结果如下
<rule id="opt_option1">
<expression><![CDATA[ #{event:command} == 'Option 1' ]]></expression>
<actions>
<action ref="set_command"/>
</actions>
</rule>
<rule id="opt_option2">
<expression><![CDATA[ #{event:command} == 'Option 2' ]]></expression>
<actions>
<action ref="set_command"/>
</actions>
</rule>
<rule id="special_opt_option3">
<expression><![CDATA[ #{event:command} == 'Option 3' ]]></expression>
<actions>
<action ref="special_action"/>
</actions>
</rule>
实例
下面两个示例展示了使组件配置更易于理解的高级方法。
输入字段分组
您可以使用 inputType "容器 "对多个输入字段进行分组。这样可以使视觉效果更加清晰,还能实现复制一组元素等功能。
下面是一些具体属性及其说明。
容器组: 区分不同类型的组。可用于在工作流标记中对容器进行复查。
可重复: 允许用户创建组的副本。这些副本可以单独更改,从而实现可重复元素。
可折叠: 这样可以将组最小化,只显示标题。
可删除: 从配置中删除容器。它会自动为复制的容器设置,不应在基本容器中使用。
可编辑: 允许用户更改容器的标题。
"base_sensor": {
"title": "Sensor 1",
"inputType": "container",
"containerGroup": "sensors",
"repeatable": true,
"collapsible": true,
"deleteable": false,
"editable": true,
"value": {
"sensor_shown": {
"title": "Value Shown",
"inputType": "checkbox-input",
"value": false,
"showIfComputed": true
},
"sensor_type": {
"inputType": "file-upload",
"title": "Icon",
"accept": "image/png",
"multiple": false,
"value": "",
"showIfComputed": true
},
"sensor_unit": {
"title": "Unit",
"inputType": "textinput",
"value": "rpm",
"showIfComputed": true
},
"sensor_json_path": {
"title": "JSON Path ",
"inputType": "textinput",
"value": "rpm",
"showIfComputed": true
}
},
"showIfComputed": true,
"container_editing": false,
"container_opened": true
}
输入字段的条件显示
可以使用 "showIf "属性来定义一个条件,在该条件下,输入字段应该显示或隐藏。例如,假设您的组件有一个可选功能,可以进行详细配置。如果该功能根本没有被使用,那么您就不想显示详细的配置参数。
我们来看一个例子:
{
"Camera":{
"use_camera":{
"title": "Use Device Camera",
"inputType": "checkbox-input",
"value": "false"
},
"zoom_level":{
"title": "Zoom Level",
"inputType": "dropdown-input",
"showIf": "root.Camera.use_camera.value",
"value": { "name": 1 },
"elements": [
{
"name": 1
},
{
"name": 2
},
{
"name": 3
}
]
},
"show_zoom_level": {
"title": "Show Zoom Level",
"inputType": "checkbox-input",
"showIf": "root.Camera.use_camera.value && root.Camera.zoom_level.value.name > 1",
"value": "false"
},
"timeout":{
"title": "Camera Timeout (ms)",
"showIf": "root.Camera.use_camera.value",
"inputType": "textinput",
"value": 5000
}
}
}
下面是预期输出结果。
由于复选框设置为假,所有其他输入字段都不会显示。如果设置为 "true",除了 "显示缩放级别 "复选框外,其他所有输入框都会显示,因为只有当缩放级别大于 1 时,该复选框才会显示:
任务
作业 1:
- 为标题以及两个按钮上的图片和文字添加配置字段。
- 只有当两个按钮都有图像时才显示图像。如果只有一个按钮配置了图片,则只显示文本。
下载组件(作业前)
帮助和资源
访问布局文件中的配置
在布局标记的属性中,您可以一如既往地访问配置:
<Button Name="§{ ... }§" .../>
但是,对于块辅助函数,您必须使用像这样的<Script>:
<Script>§{#if ...}§</Script>
<Button .../>
<Script>§{/if}§</Script>
还需注意的是,您将无法在所有其他标记中使用<Script>
标记。下面是一个无效示例:
<Button>
<Script>§{#...}§</Script>
...
<Script>§{/...}§</Script>
</Button>
最后,如果由于一个元素名称存在两次,但您确定预编译后每次只存在其中一个,而导致条件语法错误 "重复唯一值
",您可以忽略该语法错误。
解决方案
下面是一个布局示例解决方案:
<LayoutModel Name="ChoiceScreen" Page="DefaultMaster" Orientation="Vertical">
<Content PlaceHolder="Content" Weight="1" Orientation="Horizontal">
<Script>§{#if (and (compare configuration.leftImage.value.image.value "!=" "") (compare configuration.rightImage.value.image.value "!=" ""))}§</Script>
<Button Name="§{configuration.leftImage.value.text.value}§" FocusOrder="0" Weight="0.5" Style="ImageButtonStyle">
<Image Name="LEFT_IMAGE" Weight="0.8" Margin="0,0,0,0" Content="§{configuration.leftImage.value.image.value}§" ScaleType="CenterCrop"/>
<Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
<Events/>
</Button>
<Script>§{else}§</Script>
<Button Name="§{configuration.leftImage.value.text.value}§" FocusOrder="0" Weight="0.5" Style="ImageButtonStyle">
<Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight="1" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
<Events/>
</Button>
<Script>§{/if}§</Script>
<Script>§{#if (and (compare configuration.leftImage.value.image.value "!=" "") (compare configuration.rightImage.value.image.value "!=" ""))}§</Script>
<Button Name="§{configuration.rightImage.value.text.value}§" FocusOrder="1" Weight="0.5" Style="ImageButtonStyle">
<Image Name="RIGHT_IMAGE" Weight="0.8" Margin="0,0,0,0" Content="§{configuration.rightImage.value.image.value}§" ScaleType="CenterCrop"/>
<Text Name="RIGHT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
<Events/>
</Button>
<Script>§{else}§</Script>
<Button Name="§{configuration.rightImage.value.text.value}§" FocusOrder="1" Weight="0.5" Style="ImageButtonStyle">
<Text Name="RIGHT_TEXT" Style="FooterButtonTextStyle" Weight="1" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
<Events/>
</Button>
<Script>§{/if}§</Script>
</Content>
</LayoutModel>
下载组件(作业后)
在这样的布局文件中访问配置可能会很混乱。如果再次遇到类似情况,不妨看看我们的通配符 widget UI 元素。该元素可在运行时动态编辑。
使用通配符部件的解决方案如下:
首先,您需要创建两个具有双按钮变体的部件模板
。
<PartTemplate Name="OptionButtonsWithImage" Orientation="Horizontal">
<Button Name="§{configuration.rightImage.value.text.value}§" FocusOrder="0" Weight="0.5" Style="ImageButtonStyle">
<Image Name="RIGHT_IMAGE" Weight="0.8" Margin="0,0,0,0" Content="§{configuration.rightImage.value.image.value}§" ScaleType="CenterCrop"/>
<Text Name="RIGHT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
<Events/>
</Button>
<Button Name="§{configuration.leftImage.value.text.value}§" FocusOrder="1" Weight="0.5" Style="ImageButtonStyle">
<Image Name="LEFT_IMAGE" Weight="0.8" Margin="0,0,0,0" Content="§{configuration.leftImage.value.image.value}§" ScaleType="CenterCrop"/>
<Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight=".2" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
<Events/>
</Button>
</PartTemplate>
<PartTemplate Name="OptionButtonsText" Orientation="Horizontal">
<Button Name="§{configuration.leftImage.value.text.value}§" FocusOrder="0" Weight="0.5" Style="ImageButtonStyle">
<Text Name="LEFT_TEXT" Style="FooterButtonTextStyle" Weight="1" MaxSize="30" Content="§{configuration.leftImage.value.text.value}§"/>
<Events/>
</Button>
<Button Name="§{configuration.rightImage.value.text.value}§" FocusOrder="1" Weight="0.5" Style="ImageButtonStyle">
<Text Name="RIGHT_TEXT" Style="FooterButtonTextStyle" Weight="1" MaxSize="30" Content="§{configuration.rightImage.value.text.value}§"/>
<Events/>
</Button>
</PartTemplate>
您的LayoutModel
只包含 "WildcardWidget"。
<LayoutModel Name="ChoiceScreen" Page="DefaultMaster" Orientation="Vertical">
<Content PlaceHolder="Content" Weight="1" Orientation="Horizontal">
<WildcardWidget Name="Options" PartTemplateName="OptionButtonWithImage" Weight="1"/>
</Content>
</LayoutModel>
最后,在工作流程中,根据配置设置要使用的部件模板:
<mapping>
<ui_element name="Options">
<param name="parttemplatename">§{#if (and (compare configuration.leftImage.value.image.value "!=" "") (compare configuration.rightImage.value.image.value "!=" ""))}§OptionButtonsWithImage§{else}§OptionButtonsText§{/if}§</param>
</ui_element>
</mapping>
这样,从布局文件中访问配置时就不会出现语法错误和特殊情况。
使用通配符小工具下载解决方案(作业后)。