要看懂/userguide/index.zul是如何实现导航的,这里有一些知识必须能够首先要理解和掌握才行。
一、ZK指令
XML处理指令描述了如何处理ZUML页面。包括page、init、component和taglib等等,这里我们了解最常见的几种处理指令就可以了。
page指令描述了页面的属性,可以将page
指令放置在XML文档的任何地方,但是language
属性只有当指令位于最高层次时才是有意义的,也就是说,处于根组件的层次。
component指令为某一页面定义新的组件。使用此指令定义的组件,仅对于使用该指令的页面是可见的。为了定义在所有组件中可以使用的组件,可是使用附加语言插件(language addon),即一个XML文件(/WEB-INF/zk.xml),用来定义在Web应用程序中所有页面都可使用的组件。
component指令有两种方式:通过宏和通过类(by-macro and by-class)。其中通过宏来定义组件又分为两种,内联宏和常规宏,它们的区别在于:内联宏的行为就像内联扩展(inline-expansion),若遇到了内联宏,则zk不会创建宏组件,相反,它会内联扩展定义在URI内的组件,换言之就像直接把内联组件的内容插入到目标页面。而对常规宏,zk将会创建一个真实的组件(称为宏组件)来显示常规宏中定义的组件,即宏组件将会作为定义在常规宏内组件的父组件被创建。常规宏允许开发人员提供额外的API并且对组件的用户隐藏实现细节,每个常规宏组件均是一个ID空间所有者,所以不必担心常规宏组件会和其它的组件名字冲突。下面是内联宏的一个例子:
username.zul
<!--MacroDef username.zul-->
<row>
Username<textbox id="${arg.id}" value="${arg.name}"/>
</row>
demo.zul
<?component name="username" inline="true" macro-uri="username.zul"?>
<grid>
<rows>
<username id="ua" name="John"/>
</rows>
</grid>
demo.zul的等价页面
<!--等价页面-->
<grid>
<rows>
<row>
UserName:<textbox id="ua" value="Jhon"/>
</row>
</rows>
</grid>
init指令有两种格式。第一种格式是指定一个类(要实现org.zkoss.zk.ui.util.Initator接口)用于处理具体应用(application-specific)的初始化,一旦指定,在页面被赋值(evaluated)前,此类的实例会被创建,并且其doInit
方法会被调用,另外,页面被赋值(evaluated)完毕后,doFinally
方法会被调用。当例外发生时,doCatch
方法会被调用。因此,init
指令并不限于初始化,你可以将其用于清理及错误处理。第二种格式是指定一个zscript文件用于处理具体应用(application-specific)的初始化。
variable-resolver指令,为zscript解释器指定一个变量分解器(variable resolver )用以分解未知变量。被指定的类必须实现 org.zkoss.xel.VariableResolver
接口。你可以使用多个variable-resolver指令以指定多个变量分解器。声明靠后的分解器有更高的优先级。下面是一个ZK结合Spring框架的例子,它分解了在Spring框架中声明的Java Beans,这样我们可以直接访问到它们。
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
别的指令在这里不再赘述。
二、事件监听器(EventListener)
org.zkoss.ui.event.EventListener描述了一个事件监听器,如果一个事件监听器被注册到组件中(Component.addEventListener(String evname,EventListener listener),那么当在这个组件上有一个事件发生时,此监听器将被通知到。如下是此接口的定义,它是相当简单的:
public interface EventListener {
public void onEvent(Event event) throws Exception;
}
如果一个事件监听器同时实现了Deferrable接口且isDeferrable()返回true,那么此监听器被认为是一个延时事件监听器,如果一个事件监听器实现了Express接口,那么此监听器在所有其它的监听器被通知之前被通知,甚至在zuml页面中用onXxx属性声明的监听器也要在它的后面被通知到,也就是说此监听器的优先级被提高了。
GenericEventListener是EventListener的默认实现,它的子类可以更加直观地用onXxx的形式表示事件处理方法,而GenericEventListener中onEvent方法的实现会自动地把事件导航到相应的方法(主要是依据名称),另外GenericEventListener还提供了一个非常便利的方法,bindComponent(Component c)以便于把一个目标事件组件绑定到事件监听器上,这样在这个组件上发生的事件就会被事件监听器监听到。
三、Composer(设计者)与ComposerExt
Composer用于初始化组件,而ComposerExt在Composer的基础上增加了更多的控制,需要指出的是实现了ComposerExt接口的组件必须也同时实现Composer,反之不成立。与Composer接口相关的ZK属性是apply。如下是Composer的定义:
public interface Composer {
public void doAfterCompose(Component comp) throws Exception;
}
为了说明Composer的用途必须首先了解一下ZK Loader加载组件的顺序:
1、如果Composer也同时实现了ComposerExt,调用ComposerExt的doBeforeCompose(Page p,Component c,ComponentInfo ci)方法。
2、创建组件(调用UiFactory.newComponent(Page p,Component c,ComponentInfo ci))
3、如果Composer也同时实现了ComposerExt,调用ComposerExt的doBeforeComposeChildren(Component comp)。
4、创建组件的所有孩子。
5、在组件的所有孩子(即子组件)被创建完成后,调用doAfterCompose(Component c)
6、如果需要的话发送onCreate事件。
AfterComposer与Composer的区别:前者只能被组件本身实现,而Composer是用于初始化组件(可以实现AfterComposer也可以不实现)的控制器。
GenericComposer是Composer的默认实现,它继承自GenericEventListener,可以看出它同时又是一个事件监听器,comp上产生的事件它都会监听到。
abstract public class GenericComposer extends GenericEventListener implements Composer{
public void doAfterCompose(Component comp) throws Exception {
//bind this GenericEventListener to the supervised component
bindComponent(comp);
}
}
GenericAutowireComposer扩展了GenericComposer,它实际上是定义了若干隐含对象,例如protected Desktop desktop,即组件对应的桌面。这些隐含对象对于组件来说是肯定可以访问的,比如前面定义的桌面对应着Component.getDesktop(),问题是现在需要把这些隐含对象对应到GenericAutowireComposer,使这些隐含对象对于它以及它的子类均是可见的,其实这在GenericAutowireComposer中只用一行代码就做到了:
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
//wire variables to reference fields (include implicit objects)
Components.wireVariables(comp, this);
}
注意:上面代码的注释非常精炼,说明了Components.wireVariables(comp, this)的目的,我个人的理解是(不一定十分准确):只要某一变量对于comp是可见的,并且在GenericAutowireComposer或其子类中有相应名称的字段(或称域、成员变量),那么上述方法调用就会把comp中可见的变量的值赋给GenericAutowireComposer或它的子类的同名字段,当然毫无疑问这肯定是通过反射机制来实现的。
啰里啰唆说了这么多,其实GenericAutowireComposer的职责就是使得对组件可见的隐含对象以及变量能够被GenericAutowireComposer及其子类的同名属性引用到。
注意:1、由于GenericAutowireComposer持有组件的引用,所以单例的Composer不能被多个组件共享。2、应该把GenericAutowireComposer的子类定义在单独的Java文件中,而不是定义在zuml页面的zscript元素中,看来BSHInterceptor的工作原理和Java编译器与虚拟机还是有差别的。
GenericForwardComposer是GenericAutowireComposer的子类,它主要完成一些导航的功能,通过继承此类,我们就可以书写类似onXxx$compId的事件处理方法以监听标识符(id)为compId的组件产生的onXxx事件,也就是说,继承自此类的监听器不仅可以监听它所在的组件上产生的事件,还可以监听它所在的组件的子组件的事件,当然方法的命名需要遵循特定的规则。下面是一个例子:
package cn.asix.zkdemo;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Label;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;
public class MyForwardComposer extends GenericForwardComposer {
private Textbox mytextbox;
private Window self; //embeded object, the supervised window "mywin"
private Page page; //the ZK zuml page
private Label mylabel;
public void onChange$mytextbox(Event event) {
mylabel.setValue("You just entered: "+ mytextbox.getValue());
}
}
ZUML页面:
<?page title="GenericForwardComposerDemo" contentType="text/html;charset=UTF-8"?>
<zk>
<window title="GenericForwardComposerDemo" border="normal" apply="cn.asix.zkdemo.MyForwardComposer">
<textbox id="mytextbox"/>
<label id="mylabel"/>
</window>
</zk>
onChange$mytextbox可以监听id标识为mytextbox的textbox上产生的onChange事件。
四、关于变量与表达式
就像在JSP中一样,可以在zuml页面的任何部分使用EL表达式,但除了属性的名字、元素以及处理指令。语法:${exp}。
EL表达式中的变量对于当前的组件必须是可见的,即Component.containsVariable(String name,boolean local)返回true。例如:
package cn.asix.zkdemo;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.metainfo.ComponentInfo;
import org.zkoss.zk.ui.util.Composer;
import org.zkoss.zk.ui.util.ComposerExt;
public class SimpleComposer implements Composer,ComposerExt {
public void doAfterCompose(Component comp) throws Exception {
}
public ComponentInfo doBeforeCompose(Page arg0, Component arg1,
ComponentInfo arg2) {
return arg2;
}
public void doBeforeComposeChildren(Component comp) throws Exception {
comp.setVariable("person", new Person(), false);
}
public boolean doCatch(Throwable arg0) throws Exception {
arg0.printStackTrace();
return false;
}
public void doFinally() throws Exception {}
public class Person{
private String name;
private int age;
public static final int DEFAULT_AGE=20;
public Person(){
this.name="defaultName";
this.age=DEFAULT_AGE;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
}
ZUML代码:
<?page title="GenericForwardComposerDemo" contentType="text/html;charset=UTF-8"?>
<zk>
<window title="SimpleComposerDemo" border="normal" apply="cn.asix.zkdemo.SimpleComposer">
<button label="${person.name}" onClick="alert(person.age);"/>
</window>
</zk>
在上面的例子中,由于window是一个ID空间,而SimpleComposer在doBeforeComposeChildren方法中将变量person添加到了window所对应的命名空间中:comp.setVariable("person",new Person(),false),因此这个变量对于在window所在的ID空间中的子组件button也是可见的,所以label="${person.name}"等价于label="defaultName",而onClick="alert(person.name)"等价于onClick="alert(20)",这里有一点不一样,label中的内容属于EL表达式,而onClick中的内容属于脚本代码,不过定义在命名空间中的变量对于属于同一个命名空间的脚本代码及EL表达式都是可见的。关于组件的命名空间有这样的解释:1、每一个ID空间都有一个确切的命名空间与之对应;2、定义在命名空间中的变量对于属于同一个命名空间的脚本代码及EL表达式都是可见的。
The End.
分享到:
相关推荐
整理的比较全面的zul页面注解和java注解,初学zk框架的朋友可以看看,了解注解的功能,便于框架的学习。
使用 Eclipse 可以提高开发效率,并有助于深入理解 ZK 的工作原理。官方文档提供了详细的集成指南: - [ZK 与 Eclipse 集成指南](http://www.zkoss.org/smalltalks/eclipse/ek.html) 通过这个指南,你可以轻松地将...
- **其他资源**: 包括 `User Guide`、`User Reference` 和 `zk-API` 文档等,均可在官网或 FTP 下载。 #### 四、总结 本指南为 zk 初学者提供了一套完整的入门流程,包括 Zk Studio 的安装、Zk 包的配置、动态 Web...
《Publishing.ZK.Developers.Guide》是一本专注于ZK框架开发的指南,由Packt Publishing出版。这本书深入介绍了ZK,一个基于组件的Java Web用户界面(UI)框架,用于构建富互联网应用程序(RIA)。ZK以其事件驱动、...
首先,"ZK-Studio_userguide.pdf"是关于ZK Studio的用户指南,ZK Studio是ZK提供的一个集成开发环境,用于简化ZK应用的创建、调试和部署过程。该文档将详细介绍如何安装和配置ZK Studio,以及如何使用其各种功能,如...
在使用zk框架开发的过程中,尝试加载`/group/salegroup/index.zul`页面时遇到了`SAXParseException:Contentisnotallowedintrailingsection`的错误。 **解决方案**: 1. **分析原因**: - 错误提示表明XML文档结构...
ZUL Studio是一款强大的Java开发工具,专为ZK框架提供集成开发环境。ZK是一个轻量级、基于组件的Web应用框架,它简化了创建富客户端用户界面的复杂性,尤其是那些需要高度交互和响应性的应用程序。在本安装文件中,...
5. **视图**:ZK的ZUL页面,如`todo.zul`和`index.zul`,定义用户界面的布局和组件。 6. **配置**:设置Spring的配置文件(如`applicationContext.xml`)和Web应用的部署描述符(`web.xml`),配置数据源、扫描包、...
开发人员可以使用ZK提供的组件(如`<chart>`标签)在ZUL(ZK User Interface Language)文件中创建图形,同时结合后端数据处理和传输,以实现动态的图表展示。ZK还支持事件处理和数据绑定,使得前端和后端的数据交互...
这个示例通常包括一个简单的ZUL(ZK User Interface Language)文件和一个对应的Java控制器。ZUL文件是ZK的标记语言,用于描述用户界面布局和组件。打开`index.zul`,你会看到类似以下的代码: ```zul ...
2. **profile.zul、subscription.zul、register.zul、login.zul**:这些文件是ZK Framework(ZK,一个基于组件的Java Web开发框架)的ZUL(ZK User Interface Language)文件。它们分别代表用户资料、订阅、注册和...
ZK 是一个基于 Java 的轻量级Web框架,专门用于构建富客户端的Web应用程序。它提供了丰富的用户界面组件和事件处理机制,使得开发者能够轻松创建交互式的Web应用。本篇文章将深入探讨ZK框架的基本概念、开发环境的...
ZK的脚本语言ZUL(ZK User Interface Language)也是其独特之处。ZUL是一种XML标记语言,用于定义用户界面的结构和行为。开发者可以使用ZUL来创建和控制组件,定义事件处理函数,甚至进行数据绑定。ZUL文件可以被...
- 在 `src/main/webapp` 目录下创建一个 HTML 文件,例如 `index.zul`。 - 使用 ZUML 编写简单的 UI 元素,例如按钮、文本框等。 - 在 `web.xml` 文件中配置 ZK 初始化参数。 6. **运行应用**: - 右键点击项目...
创建ZK宏需要在.zul文件中定义一个`<zk>`元素,并使用`<zk-macro>`标签来声明宏。宏内部可以包含任何ZK组件、属性、事件绑定以及样式定义。例如,一个简单的按钮宏可能如下所示: ```xml <zk> <zk-macro id=...
2. **zul.jar**:ZUL(ZK User Interface Language)是ZK框架定义的一种标记语言,用于构建用户界面。这个jar文件包含了ZUL文件解析和运行所需的类库,使得开发者能够用XML来描述界面布局和交互逻辑。 3. **zk.jar*...
4. **ZUL语言**:ZK提供了一种标记语言ZUL(ZK User Interface Language),用于定义用户界面布局和组件。ZUL文件类似于XML,用于描述组件结构和行为。 5. **Ajax技术**:ZK利用Ajax实现页面的部分刷新,提升用户...
zk框架中grid复杂表头的处理,包括实现横向滚动条、列错位、列宽度定制、早期版本IE兼容性问题导致没有分割线。 建议下载官网开源demo 【zksandbox】,下载auxheader.zul替换项目中的/zksandbox/WebRoot/grid/...