反复式流程

创建一个元素的流程可以是反复式的。通过为forEach属性一个对象集合,开发人员可以控制相关元素要被创建多少次。为了描述方便,如果一个元素被forEach属性赋值就称其为迭代元素(iterative element)。

在下面的例子中,列表项目被创建了三次。每个项目的label分别为"Best", "Better" 和 "God",

<listbox>
    <listitem label="${each}" forEach="Best, Better, God"/>
</listbox>

如果你有一个存放对象集合的变量,则可以直接为forEach属性指定它。例如,假如你有一个grades变量,如下。

grades = new String[] {"Best", "Better", "Good"};

然后可以使用forEach属性来迭代此变量。注意,你必须使用EL表达式来指定这个集合。

<listbox>
   <listitem label="${each}" forEach="${grades}"/>
</listbox>

迭代(iteration)依赖于forEach属性指定值的类型。

  1. 如果是java.util.Collection,就会迭代集合(collection)的每个元素。

  2. 如果是java.util.Map,就会迭代map中的每个Map.Entry。

  3. 如果是java.util.Iterator,就会迭代迭代器(iterator)中的每个元素。

  4. 如果是java.util.Enumeration,就会迭代enumeration中的每个元素。

  5. 如果是Object[],int[],short[],byte[],char[],float[]或double[]被指定了,就会迭代数组(array)中的每个元素。

  6. 如果是null,什么也不会产生(被忽略)。

  7. 如果被指定的不是以上类型,相关元素仅被赋值(evaluated)一次,就好像一个集合只指定了一个单 独的项目。

<listbox>
  <listitem label="${each}" forEach="grades"/>
</listbox>

each变量

在迭代中,一个变量被称为each,通过指定集合的项目被创建并且赋值。在上面的例子中,首次迭代中,each被赋值为"Best",然后是"Better",最后是"Good"。

注意each变量在EL表达式和zscript中都是可访问的。ZK将会保留以前定义的每个变量,并在迭代完每个元素后将其恢复。

forEachStatus变量

forEachStatus变量是org.zkoss.ui.util.ForEachStatus的一个实例(instance),用来保存(hold)当前迭代(iteration)的信息。也主要用于取得封闭元素的项目,这些元素已通过forEach属性赋值。

在下面的例子中,我们使用嵌套迭代元素(nested iterative elements)来产生两个listbox。

<hbox>
  <zscript>
classes = new String[] {"College", "Graduate"};
grades = new Object[] {
  new String[] {"Best", "Better"}, new String[] {"A++", "A+", "A"}
};
  </zscript>
  <listbox width="200px" forEach="${classes}">
    <listhead>
      <listheader label="${each}"/>
    </listhead>
    <listitem label="${forEachStatus.previous.each}: ${each}"
    forEach="${grades[forEachStatus.previous.index]}"/>
  </listbox>
</hbox>

注意forEachStatus变量在EL表达式和zscript中都是可访问的。

如何在事件监听器中使用 eachforEachStatus 变量

在事件监听器中使用forEachforEachStatus变量有点棘手(tricky),因为它们仅在组件创建阶段(Component Creation Phase)[35]是可用的(available)。因此,下面的例子是不正确的。当onClick监听器被调用时,each变量就不可用了。

<window title="Countries" border="normal" width="100%">
   <zscript><![CDATA[
   String[] countries = {
     "China", "France", "Germany", "United Kindom", "United States"};
   ]]></zscript>

   <hbox>
      <button label="${each}" forEach="${countries}"
         onClick="alert(each)"/> <!-- incorrect!! -->
   </hbox>
</window>

注意按钮(button)标签(label)的赋值方式是错误的,因为它们在同一阶段-----组件创建阶段(Component Creation Phase)。

同时也要注意不能在事件监听器中使用EL表达式。例如,下列代码会执行失败,因为onClick的监听器并不是Java代码(也就是说,EL表达式在zscript中是被忽略的)。

<button label="${each}" forEach="${countries}"
     onClick="alert(${each})"/> <!-- incorrect!! -->

一个解决方法:定制属性

解决方法是我们必须在某处存储each (和forEachStatus)的内容,这样当监听器执行时其内容仍是可用的。你可以将其内容存储在任何地方,但是有一个简单的方法来处理,如下:

<window title="Countries" border="normal" width="100%">
   <zscript><![CDATA[
   String[] countries = {
      "China", "France", "Germany", "United Kindom", "United States"};
   ]]></zscript>

   <hbox>
      <button label="${each}" forEach="${countries}"
      onClick="alert(self.getAttribute(&quot;country&quot;))">
         <custom-attributes country="${each}"/>
      </button>
   </hbox>
</window>

就像按钮(button)标签(label),定制属性(custom attributes)的属性在组件创建阶段 (Component Creation Phase)被赋值(evaluated),所以在这里你可以使用each。然后,它被存储在一个定制属性,这个定制属性会在组间存在的期间一直有效(直到组件被移除)。



[35] 参考组件活动周期 (Component Lifecycle) 一章获取细节。