架构
ZK包括一种基于AJAX机制用来实现自动的交互性,一套丰富的基于XUL的组件用以丰富可用性,和一种的标记语言用来简化开发。
基于AJAX的机制包括三个部分,描绘如下:ZK 加载器(ZK loader),ZK AU引擎(ZK AU Engine) [17] ,和ZK客户端引擎(ZK Client Engine)。
基于用户的请求,ZK 加载器(ZK loader)加载一个ZK页面,解释它,并将结果送到HTML页面来响应URI请求。ZK页面是用一种被称为ZUML的标记语言写成的。ZUML,就像HTML,被用来描述什么组件被创建,以及如何把它们呈现出来。这些组件一旦被创建,就会一直处于可用状态知道会话超时。
然后ZK AU[18] 引擎(ZK AU Engine )和ZK客户端引擎(ZK Client Engine)作为投手和捕手一起工作。它们将在浏览器端发生的事件送到运行在服务器端的应用程序,然后更新浏览器段的DOM树,基于组件如何被应用程序操纵。这种方式即所谓的事件驱动编程模型。
执行流
1. 当用户在浏览器中键入一个URL或点击一个超链接时,一个请求便被送到了Web服务器,如果URI符合ZK的配置[19],ZK 加载器则援引担任这一要求 。
2. ZK 加载器(ZK loader)加载指定的页面然后解释它,以据此创建和适的组件。
3. 当解释完整个页面后,ZK 加载器(ZK loader)将结果送到一个HTML页面。然后这个HTML页面被送回浏览器和ZK客户端引擎(ZK Client Engine)[20]一起。
4. ZK客户端引擎(ZK Client Engine)坐落在浏览器,以监视由客户的活动触发的事件,例如挪动鼠标,或改变某个值。一旦监测到,它就通知ZK AU引擎通过发送一个ZK请求[21]。
5. 当从客户端引擎接到ZK请求后,如果有需要的话AU引擎就更新相应组件的内容。然后,AU引擎通过调用相关的事件处理程序(如果有的话)来通知应用程序。
6. 如果应用程序选择改变组件的内容,添加或移动组件,AU引擎通过ZK响应(ZK responses)将更新后组件的新内容送至客户端引擎。
7. 这些ZK响应实际上是一些命令,这些命令指示客户端引擎如何更新DOM树的内容。
加载页面的活动周期: 页面初始阶段,组件创建阶段,事件处理阶段及响应阶段
页面初始阶段
如果并没有定义这样的处理指令,此阶段会被跳过。
对于每个init
处理指令都有一个class
属性,一个指定类的实例(instance)将会被创建,然后它的doInit
方法将会被调用。当然,这个类要做什么取决于你的应用程序的需求。
<?init class="MyInit"?>
初始处理指令的另一种形式是使用zscrtpt
属性指定包含脚本代码的文件如下。那么在页面初始阶段这个文件将会被解释。
<?init zscript="/my/init.zs"?>
请注意在这个阶段页面并没有被附加到桌面。
组件创建阶段
在这个阶段,ZK加载器(ZK loader)解释一个ZUML页面,它创建并初始组件。这需要以下的一些步骤:
1. 对于每个元素,它检查if
和unless
以确定元素是否有效。如果无效,此元素及其所有的子元素将 会被忽略。
2. 如果forEach
被指定并伴随着一个项目的集合,ZK将会为集合中的每个项目重复以下步骤。
3. 基于元素名字,或使用use
属性指定的类(如果有的话)创建一个组件。
4. 基于在ZUML页面属性指定的顺序依次初始成员。
5. 解释嵌套的元素(nested elements)并重复整个过程。
6. 调用afterCompose
方法如果组件实现了org.zkoss.zk.ui.ext.AfterCompose
[30]接口。
7. 在所有的组件都被创建后,onCreate
事件被送到该组件,这样之后应用程序可以初始划化一些元素的内容。注意,onCreate
事件首先为子组件公布。
[注]: 开发人员可以通过监听onCreate
事件或实现AfterCompose
接口来完成一些特定应用程序的初始化。AfterCompose
在组件创建阶段(the Component Creation Phase)被调用,而onCreate
事件是由事件监听器来处理的。一个事件监听器者可以自由地挂起或恢复执行(例如创建对话框(modal dialogs)),而由于AfterCompose
不需要派生另一个线程, 所以它快一些。
事件处理阶段
在这个阶段,ZK依次调用每个事件的监听器,这些事件已经为桌面排好队列。一个独立线程开始调用监听,这样它可以在不影响其它事件处理的情况下被挂起。
在处理过程中,一个事件可能引发其它事件
响应阶段
在所有的事件都被处理后,ZK将这些组件组成一个规则的HTML页面并将这个页面送到浏览器。
为了发送一个组件,redraw
会被调用。在这个方法中,一个组件的实现(implementation)并不会更改其它组件的内容。