我仍然没有找到详细的文档,但我已经做了大量的实验并得出了以下结论......
(注意:我的示例使用了我开发的 Sencha GXT 中的一些概念)
<define-property> 用于定义属性及其可能的值,但对于实际使用的值而言,这并不是最后的决定。*.gwt.xml 文件的层次结构中的每个属性都应该有一个这样的定义。
<set-property> 不会将属性设置为 A 值,但会创建一种规则,其中包含该属性的 POSSIBLE 值的集合(理想情况下是 <define-property> 中定义的子集)。给定属性的最后一个 <set-property> 声明获胜。当心!如果您在 <inherits> 之后使用 <set-property> (继承模块),您可能/将覆盖您继承的任何规则。请注意,有条件规则和无条件规则。例如,
<set-property name="gxt.user.agent" value="ie10, ie11, gecko1_9, safari5, chrome"/>
... 将无条件声明,在确定排列时,属性“gxt.user.agent”可以具有任何列出的值。反过来,
<set-property name="user.agent" value="safari">
<any>
<when-property-is name="gxt.user.agent" value="safari5" />
<when-property-is name="gxt.user.agent" value="chrome" />
</any>
</set-property>
当“gxt.user.agent”是“safari5”或“chrome”时,将声明 user.agent 只能是“safari”。顺序似乎很重要,因此您需要在依赖项规则之后声明依赖属性的规则。循环依赖会使编译失败。您可以创建许多条件规则,只要它们不相互矛盾。我还不知道如果他们这样做会发生什么,但我猜最后宣布的人会赢。
请注意,条件规则还可以指定多个可能的值。例如(仅插图,可能与您的需求不符):
<!-- On desktops we do all browsers including IE -->
<set-property name="gxt.user.agent" value="safari5, chrome, gecko1_9, ie11">
<when-property-is name="gxt.device" value="desktop" />
</set-property>
<!-- ... but on tablets and phones we exclude IE -->
<set-property name="gxt.user.agent" value="safari5, chrome, gecko1_9">
<any>
<when-property-is name="gxt.device" value="tablet" />
<when-property-is name="gxt.device" value="phone" />
</any>
</set-property>
您可以使用 <any> 和 <all> 创建复杂/复合标准。这些可以相互嵌套。
如何使用它来精确控制排列?您可能不需要它,但它帮助我从定义如下两个属性开始:
<define-property name="custom.use.case" values="case1, case2, ..."/>
<property-provider name="helix.product.mode"><![CDATA[
var useCase = ...; // JavaScript code to determine the use case
return useCase;
]]>
</property-provider>
<define-property name="custom.permutation" values="perm1, perm2, ..."/>
第一个属性定义用例。上面我有一种方法可以在运行时确定它。您可能不会也可能会跳过它。它还可以作为定义其他所有内容的起点,因为我们可以根据用例定义所有其他属性。例如:
<!-- Case 1 restrictions -->
<set-property name="gxt.device" value="desktop">
<when-property-is name="custom.use.case" value="case1" />
</set-property>
<set-property name="gxt.user.agent" value="chrome, safari5, gecko1_9, ie11">
<when-property-is name="custom.use.case" value="case1" />
</set-property>
...
<!-- Case 2 restrictions -->
<set-property name="gxt.device" value="tablet, phone">
<when-property-is name="custom.use.case" value="case2" />
</set-property>
<set-property name="gxt.user.agent" value="chrome, safari5, gecko1_9">
<when-property-is name="custom.use.case" value="case2" />
</set-property>
...
<!-- Case 3 restrictions -->
<set-property name="gxt.device" value="tablet, phone">
<when-property-is name="custom.use.case" value="case3" />
</set-property>
<set-property name="gxt.user.agent" value="safari5">
<when-property-is name="custom.use.case" value="case3" />
</set-property>
...
etc.
接下来要做的是折叠除custom.permutation 之外的所有属性,因为我们只希望 custom.permutation 驱动排列:
<collapse-property name="custom.use.case" values="*" />
<collapse-property name="gxt.device" values="*" />
<collapse-property name="gxt.user.agent" values="*" />
<collapse-property name="user.agent" values="*" />
<collapse-property name="user.agent.os" values="*" />
这种方法允许对“排列”及其内部复杂性进行极细粒度的控制,有些人称之为“软排列”。每个可能的“custom.permutation”属性值都会有一个排列。如果您很好地设置了上述规则,则每个排列中只会包含所需的“软排列”。
请注意,实际排列和软排列都需要成本。拥有许多软排列(是否分组为实际排列)会降低编译性能和它们所在排列的运行时代码大小。不要忽略这一点,尤其是当您有许多属性时。实际排列具有更高的编译和链接时间成本(但与将许多软排列组合成分组的实际排列相比,拥有更多排列会减少每个排列的大小)。
如果使用 GXT,从版本 4 开始,您会注意到它添加了 gxt.device 属性,该属性具有桌面、平板电脑和手机等值。这导致我们的编译时间在升级到 GXT 4 后增加了大约 6-7 倍,因为我们的排列失控了。有些最终是为在 Mac OS 平板电脑上运行的 Internet Explorer 而设计的。您可以体会到对不存在的用例进行排列是多么浪费时间。通过实施上述方法,我们能够将 GWT 编译时间减少到原始时间的一半左右,或者比 GXT 4 升级后快 10-12 倍。