博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

3.zk体系结构

Posted on 2007-04-17 14:37  daniel-shen  阅读(1131)  评论(0编辑  收藏  举报
zk体系结构:
    zk内嵌了体格基于ajax的机制进行自动的交互,一个基于xul的组件丰富可用性,一个标记语言简化开发。
    基于ajax的机制包含了三部分。 zk loader,zk au engine和zk client engine.对于用户的请求,zk loader加载zk page,然后转换成html page,发回客户端。一张zk page 是用zuml标记语言写的。zuml,类似与html,是用来描述创建什么组件,如何表现组件的。这些组件,一旦创建了,在session超时前都保持可用。
    zk au engine 和 zk client engine 的工作方式类似于棒球场上的投手和接球手。他们向服务器上正在运行的应用传递在浏览器中正在发生的事件,基于服务器操纵组件的规则更新dom树。这也被称为事件驱动的编程模式。
    工作流程:
    1.当用户在浏览器中输入了url或者点击了超级链接,一个请求发送到了服务器。如果rul满足条件(需要zk loader),zk loader被调用进行处理请求。
    2.zk loader加载指定的page,翻译page创建指定的组件。
    3.翻译完了整张页面以后,zk loader 将结果转成一张html page。这张page被发送到有zk client engine的浏览器。
    4.zk client engine安静的在浏览器中侦察用户触发的时间,如移动鼠标,修改值什么的,一旦侦察到了,它就通过发送zk 请求唤醒zk au engine。
    5.从client engine那接受到zk请求后,在必要的情况下,au engine 更新相应组件的内容。然后,au engine唤醒应用中相关是事件处理器。
    6.如果应用选择修改,增加,移除组件的内容,au engine通过zk回应发送被改变的组件的新的内容到client engine.
    7.这些zk回应指导client engine如何去更新dom树。
   
组件,页面和桌面
    组件:一个组件就是是一个UI 对象,如label,button,tree.它定义了用户接口的视图和动作。通过操纵它们,程序员控制如何在客户端上展现应用。一个组件必须扩展org.zkoss.zk.ui.Component接口。
    页面:一张页面是组件的集合。页面配置了属于它的组件,定义了组件在浏览器中出现的位置。当zk loader解释zuml page时,页面被自动创建。
    桌面:一张zuml page可能间接或直接的包含其他的 zuml page。当对于一个url 请求创建了多个页面的时候,它们被称为桌面(org.zkoss.zk.ui.Desktop).即桌面就是服务于同一个url的页面集合。
    当zk应用运行的时候,桌面上可能多个页面被加入或删除,就如同页面上的组件被增加或删除类似。
    createComponent方法:
    注意页面和桌面都是在后台创建和删除。但是没有api去创建和删除他们。页面创建是每次zuml加载的时候。页面删除是zk发现它再也不被关联的时候。桌面创建是在第一次zuml page加载的时候,删除是在太多的桌面在指定的session中创建的时候。
    org.zkoss.zk.ui.Executions类中createComponents方法只能创建组件而不是方法,即使是在加载zuml文档的时候。
组件的森林
    一个组件至多有一个父亲,可能有多个孩子。一些组件只接受特定类型的组件作为孩子,而一些组件只能成为特定组件的孩子,而有些却不允许有任何孩子。举例来说,xul的listbox只接受Listcols和Listiterm。
    一个没有父亲的组件被称为根组件。一个页面可能含有多个根组件,可以通过getRoots函数得到。
    组件:一个视图和java对象
    除了作为服务器上的一个java对象,组件也在浏览器扮演了视图角色,当且仅当它属于页面的时候。当组件与页面关联的时候,它的视图部分就被创建了。当组件不和页面关联的时候,其视图部分也被移除了。
    有两个方法可以放组件关联到页面。1.你可以调用setPage方法使一个组件成为指定页面的根组件。2.你可以调用setParent,insertBefore或者 appendChild方法使之成为其他组件的孩子。
    类似的,你可以通过setPage函数设置null把根组件从页面分离。当然,其孩子也和页面分离了。
    标示符:
    每一个组件都含有一个标示符(可以通过getId获得).它是组件被创建的时候自动获得的。程序员可以在任何时候修改它,没有任何限制。可是,一旦一个标示符被指定了,程序员可以在zuml page中通过java 代码或el表达式进入它。
<window title="Vote" border="normal">
Do you like ZK? <label id="label"/>
<separator/>
<button label="Yes" onClick="label.value = self.label"/>
<button label="No" onClick="label.value = self.label"/>
</window>
    UUID:
    一个组件有另一个标示符叫做UUID(Unicersal Unique ID),这个才是程序员真正需要的。
    在浏览器组件和client engine通过UUID来操纵dom,和与服务器通信。其实,dom元素的id属性就是UUID.
    UUID是在组件被创建的时候生成的。它是不可变的,except the identifiers of components for representing HTML tags.  
    HTML相关的组件处理UUID和其他的组件不同:UUID和ID是相同的。如果你修改HTML相关的组件de  ID,则UUID也会被相应的修改。所以,旧试的javascript代码和servlet仍旧不加修改的保持工作。
    THE ID SPACE:
    将一个完整的视图分解成多个zuml页面是很普通的做法。举个例子,一个页面来显示订购单,一个对话狂用来输入支付条件。如果所有的组件在同一个桌面上有唯一的标示的话,程序员必须在所有的页面在一个桌面上保持这种唯一性。
    引入ID空间来解决这个问题。ID空间是桌面组件的子集。唯一性只需要在ID空间上面得到保证即可。
    一种简单的ID空间的形式是window(org.zkoss.zul.Window).window的所有子孙组件(包括window自己)形成一个独立的ID空间。因此,你只需要在页面上使用window作为组件的最上级,这样程序员就可以保持页面独立的唯一性。
    更一般的情况,任何组件可以形成一个ID空间,只要实现了org.zkoss.zk.ui.IdSpace接口。页面也实现这个接口,所以它也是空间的所有者。
    ID空间的最顶端组件也称为ID空间的所有者,可以通过component接口的getSpaceOwner方法返回。可以通过getFellow方法得到同个空间的成员。
    值得注意的是,getFellow方法可以由空间中的所有成员使用。getSpaceOwner方法也是的。
    The org.zkoss.zk.ui.Path class provides utilities to simplify the location of a component among ID spaces. Its use is similar to java.io.File.
     Path.getComponent("/A/C/E");
 new Path("A/C", "E").getComponent();
    在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>
    定义的变量和函数被存储在包含他们的ID空间中,在上面的情况下,myvar和myfunc都存储在window a中。
    子空间可以看见父空间中定义的变量和函数。
    有意思的是,当assignment发生时,zk会首先定位变量。如果找到了,马上更新。如果没有找到,则新建一个变量。所以,在下面的例子中var2是”def“,而第二个var1和第一个是相同的。
<window id="A">
<zscript>var1 = "abc";</zscript>
<window id="B">
<zscript>var1 = "def";</zscript>
</window>
<zscript>var2 = var1;</zscript>
</window>
To declare a variable local to a namespace no matter its parent ID space defined it or not,use the following format:
MyClass myvar = myvalue,所以,在下面的例子中,var2是"abc"。in other words,the second var1 is created in the id space of window b,while the first var1 is created in the id space of window a.
<window id="A">
<zscript>var1 = "abc";</zscript>
<window id="B">
<zscript>Object var1 = "def";</zscript>
</window>
<zscript>var2 = var1;</zscript>
</window>
    zscript 和 el 表达式
    在zscript中定义的变量是能够被el表达式看见的,只要他们在一个id空间中。
<window>
<zscript>
String var = "abc";
</zscript>
${var}
</window>

<window>
abc
</window>
效果相同
    下面的变量在同一个空间中的是看不见的,它们被{}包围了
<zscript>
{
String var = "abc"; //visible only inside of the curly brace
}
</zscript>
事件:
    事件(org.zkoss.zk.ui.event.Event)是用来通知应用发生了什么。每一个事件被不同的类描述。举个例子,org.zkoss.zk.ui.event.MouseEvent表示了鼠标的动作,像单击。
    为了对事件做出回应,应用必须在事件上注册一个或多个监听。有两中方法。1.指定onXXX在标记语言中。2.给组件调用addEventListener方法。
     作为补充org.zkoss.zk.ui.event.Event类有sendEvent()和postEvent()方法。
    桌面和事件处理
    像上面提到的,桌面是服务于一个url请求的页面的集合。一个桌面也是一个事件监听可以进入的范围。  
    一个事件是和特定的桌面联系在一起的。zk基于关联的桌面隔离事件,将事件压入隔离的队列。因此,一个桌面的事件被顺序的处理。即,不同桌面的事件的执行关系是水平的。
    一个事件的监听器被允许进入关联的桌面的页面的任何一个组件。也被允许从一个组件转移到另一个组件上,只要是在同一个桌面上。换句话说,它不能访问其他桌面的组件。
    桌面和组件的创建
    当在一个监听器里创建了一个组件。默认的,它被指派到执行事件相关的桌面。这个指派甚至在组件没有关联到页面也会发生。这意味着,在事件监听器中产生的组件在监听器所关联的桌面上是可
以被使用的。
    当一个组件不在事件监听器中产生,它不属于任何桌面。在这种情况下,你可以关联到任何桌面只要关联发生在适当的事件监听器内。当然,一旦关联建立了,它就永远属于那个桌面了。
    在大多数应用中,很少有必要在非监听器中创建组件。可是,如果你有一个费时的操作,你可能想在后台线程中行它。然后你可能在后台准备一个组件树,当有适当的时间发生的时候把树添加到桌面上。有关long operations,请参考event listening and processing 。
    zuml和xml命名空间
    zuml是基于xml格式的语言,开发者用来描述视图的。不同的组件集合,像xul,xhtml可以被同时再一个zuml页面中使用。different markup languages could be added transparantly.如果2个或更多的组件集合被应用到同一个page,程序员需要通过xml命名空间区别它们。