将视觉表现(visual presentation)分为几个ZUML页面是很常见的。例如,一个页面用来展示订购单,一个对话框用于进入付款期。如果同一个桌面内所有的组件都是非常明确的,开发人员必须为这个桌面内所有页面维护所有标识的唯一性。为了解决这个问题,ID空间的概念被引入。一个ID空间是一个桌面的组件的子集。唯一性只在ID空间的范围内有保障。
Id空间的最简单形式是一个window(org.zkoss.zul.Window)。所有window衍生出来的组件(包括window)形成了一个独立的ID空间。因此,你可以将window作为每个页面的最高组件使用,这样,开发人员需要维护每个页面的唯一性。
更一般地说,任何组件可形成一个ID空间,只要它实现了org.zkoss.zk.ui.IdSpace接口。页面(Page)也实现了这个接口,所以它又是个空间所有者(space owner)。
一个ID空间的最高组件即为空间的所有者,可以使用Component接口中的getSpaceOwner方法来获得这个组件。
如果一个称为X的ID空间,从另外一个称为Y的ID空间衍生而来,那么X的所有者是空间Y的一部分,但从X衍生出来的部分并不是空间Y的一部分。
就像在图中描绘的一样,有三个空间:P,A 和C。空间P包括P,A,F和G。空间A包括A,B,C和D。空间C包括C和E。

在相同ID空间内的组件称为fellows,例如A,B,C和D就是同一ID空间内的fellows。
为了获得另一个fellow,可以使用IdSpace或Component接口中的getFellow方法。
请注意可以getFellow方法可以被同一ID空间内任何组件调用,并不仅限于空间所有者。同样,对于在同一空间内的任何组件,getSpaceOwner方法返回的是同样的对象,与是否是空间所有者无关。
org.zkoss.zk.ui.Path类提供了在ID空间内简化定位组件的工具。其使用凡是类似java.io.File
Path.getComponent("/A/C/E");
new Path("A/C", "E").getComponent();为了能让解释器(interpreter)直接读取到组件,命名空间(org.zkoss.scripting.Namespace)的概 念被引入。首先,每一个ID空间都有一个确切的命名空间。第二,定义在命名空间内的变量对于属于 同一个命名空间的脚本代码及EL表达式是可见的。
<window border="normal"> <label id="l" value="hi"/><zscript> l.value = "Hi, namespace"; </zscript> ${l.value} </window>
下面的例子有两个命名空间,一个属于window w1,另一个属于window w2。b1按钮的onClick事件针对window w1内定义的label,而b2按钮的onClick事件是针对窗口window w2
[24]内的定义的checkbox。
<window id="w1"> <window id="w2"> <label id="c"/> <button id="b1" onClick="c.value = "OK""/> </window> <checkbox id="c"/> <button id="b2" onClick="c.label = "OK""/> </window>
请注意命名空间是有等级的。换言之,window w2中的zscript可以看见window w1中的组件,除非她凌驾于window w2。因此,在下面的例子中button b1将会改变标签c。
<window id="w1"> <window id="w2"> <button id="b1" onClick="c.value = "OK""/> </window> <label id="c"/> </window>
除了ZK指定的添加到命名空间的组件,你可以指定自己的变量通过使用setVariable方法,这样 zscript可以直接参考(reference)它们。
除了执行代码,你可以在zscript元素中直接定义变量和函数,就像下面描绘的一样:
<window id="A>
<zscript>
Object myvar = new LinkedList();
void myfunc() {
...
}
</zscript>
...
<button label="add" onClick="myvar.add(some)"/>
<button label="some" onClick="myfunc()"/>
</window>
在zscript中定义的变量和函数存储在相应脚本语言的解释器(interpreter )中。
就像命名空间[25]一样,定义在zscript中的变量对于EL表达式都是可见的。
<window>
<zscript>
String var = "abc";
self.setVariable("var2", "xyz", true);
</zscript>
${var} ${var2}
</window>
等价于:
<window> abc xyz </window>
请注意,定义在zscript中的变量比定义在命名空间中的变量有更高的优先级。
<window>
<zscript>
String var = "abc";
self.setVariable("var", "xyz", true);
</zscript>
${var}
</window>
等价于:
<window> abc </window>
但如果你之后声明了一个同名组件,这就会令人困惑,就像下面展示的那样。
<window>
<zscript>
String var = "abc";
</zscript>
<label id="var" value="A label"/>
${var.value} <!-- Wrong! var is "abc", not the label -->
</window>因此,建议使用一些命名方式来避免这种困惑。例如,你可以为所有的解释(interpreter)变量加上前缀zs_。
另外,应该尽量使用局部变量。局部变量是和类名一起被声明的,并且只对某一范围的zscript代码可见。
<zscript> Date now = new Date(); </zscript>
你可以通过将其放在{}中使局部变量对于EL表达式不可见,如下:
<zscript>
{ //create a new logic scope
String var = "abc"; //visible only inside of the enclosing curly brace
}
</zscript>
依靠实现,一个解释器或许有确切的范围,或每个ID空间一个逻辑范围来存储这些变量和方法。出于 以上的描述,我们将它们分别称为单范围和多范围的解释器(single-scope and multi-scope interpreters)。
Java解释器(BeanShell)是一个典型的多范围解释器。[26]。它为每个ID空间创建一个独立的解释范围。例如,在下面的例子中分别为window A和B创建两个逻辑范围。因此在下面的例子中,var2仅对于window B是可见的,var1对于窗口A和B都是可见的。
<window id="A"> <zscript>var1 = "abc";</zscript> <window id="B"> <zscript>var2 = "def";</zscript> </window> </window>
通过Java解释器,你可以为一个最近ID空间(例如一个窗口window)的逻辑范围声明一个局部解释变量(interpreter variable)通过指定类名,如下例所示:
<window id="A">
<window id="B">
<zscript>
String b = "local to window B";
</zscript>
</window>
</window>下面是一个更复杂的例子,可以产生abc def。
<window id="A">
<zscript>
var1 = var2 = "abc";
</zscript>
<window id="B">
<zscript>
Object var1 = "123";
var2 = "def";
var3 = "xyz";
</zscript>
</window>
${var1} ${var2} ${var3}
</window>
Object var1 ="123"实际上是为window B创建了一个局部变量,对象是指定的。另一方面,var2 ="def"会使解释器(interpreter)在当前或更高的范围内寻找名称为var2的变量。var2变量在window A内已被定义,变量在此被重定义(overrided)。var3 ="xyz
"为窗口(winodw)B创建了一个局部变量,而window A并没有定义任何叫做var3的变量。
Ruby, Groovy 和javaScript解释器(Interpreters)并不支持多范围[27]。这就意味着定义的所有变量,就是说, Ruby存储在一个逻辑范围内(每一个解释器)。因此,定义在一个窗口中的解释变量(interpreter variables)会覆盖定义在另一个窗口中的变量,如果它们在同一个页面内。为了避免这种困惑,你可以为每个变量的名字加上与窗口相关的特殊前缀。
[提示]:每个页面都有它自己的解释器(interpreter)来为zscript代码赋值,如果一个桌面有多个页面,那么它或许有多个解释器的实例(instances of the interpreters)(每一种脚本语言)。
每种脚本语言都与一种解释器(interpreter)相关联。因此,定义在一种语言中的变量和方法对于另外一种语言是不可见的。例如在下面的例子中,变量var
1和var2属于两种不同的解释器(interpreter)。
<zscript language="Java"> var1 = 123; </zscript> <zscript language="JavaScript"> var2 = 234; </zscript>
可以通过getVariable方法获得定义在命名空间内的变量。另一方面,定义在zscript中的变量是解释它的解释的一部分,它们不是任何命名空间的一部分。换句话说,你不能通过getVariable方法获取它。
你必须使用getZScriptVariable方法来获得zscript中的定义的变量。同样,可以使用getZScriptClass和getZScriptMethod方法来获取定义在zscript中的类和方法。这些方法将会遍历所有的被加载的解释器直到指定的一个被找到。
如果你想找到某个解释器,可以使用getInterpreter方法先获得解释器,就像下面一样:
<zscript>
var1 = 123; //var1 belongs to the interpreter, not any namespace
page.getVariable("var1"); //returns null
</zscript>相反,你必须使用getZScriptVariable方法来获得zscript中的定义的变量。同样,可以使用getZScriptClass和getZScriptMethod方法来获取定义在zscript中的类和方法。这些方法将会遍历所有的被加载的解释器(interpreter)知道指定的一个被找到。
如果你想找到某个解释器,可以使用getInterpreter方法先获得解释器,就像下面一样:
page.getInterpreter("JavaScript").getVariable("some"); //interpreter for JavaScript
page.getInterpreter(null).getVariable("some"); //interpreter for default language