HTML相关组件

在同一ZUML页面内和XUL组件一起使用HTML标签有几种方式。你可以根据需求选择任意一个。 首先,你可以使用html组件嵌入HTML标签。使用此方法,HTML标签仅简单的为html组件的内容。它们会直接被送至客户端,对于ZK来说它们没有具体的意义。

第二,你可以使用XHTML(http://www.w3.org/1999/xhtml) 命名空间来从XHTML组件集内指定一个组件。换句话说, XHTML命名空间代表的相关XML元素为XHTML 组件集内的组件。就像ZUL组件集(http://www.zkoss.org/2005/zul),ZK为ZUML页面内每个XML元素创建一个实例。

第三,你可以使用本地命名空间(http://www.zkoss.org/2005/zk/native) 来代表将一个HTML标签直接送至客户端,而不是为它们创建ZK组件。这种方法更有效,但是不能动态改变。

最后一种但并非最不重要,你可以使用 inclusion (include) 和 inline frames (iframe) 嵌入一个ZUL页面,理论上可以是任何内容(不限于HTML标签)。

html组件

最简单的方式是使用称为html [43] 的XUL组件,在其中嵌入你想直接发送至浏览器的HTML标签。为了避免ZK解释HTML标签,通常要使用<![CDATA[ and ]]>将HTML标签围入其中。换言之,他们并不是子组件。而是被存储在content属性[44]内。注意在其中可以使用EL表达式。

<window title="Html Demo">
   <html><![CDATA[
      <h4>Hi ${parent.title}</h4>
      <p>It is the content of the html component. </p>
   ]]></html>
</window>

在此处将会成为元素的内容(又见org.zkoss.zul.Html类的getContent方法)。

提示: 你可以使用attribute 元素来指定XHTML片段,以代替 CDATA,如下。

<html
  <attribute name="content">
    <h4>Hi, ${parent.title}</h4>
    <p>It is the content of the html component.</p>
  </attribute>
</html

参考ZK用户界面标记语言一章attribute元素一节。

html组件会产生 HTML SPAN 标签来包围这些内容。换句话说,当提交到浏览器是时会产生下列的HTML标签。

<span id="z_4a_3">
   <h4>Hi, Html Demo</h4>
   <p>It is the content of the html component.</p>
</span>

html组件会产生 HTML SPAN 标签来包围这些内容。因此,你可以像使用其它的XUL组件一样使用它。例如,我们可以指定CSS样式,动态的改变它的内容。

<html id="h" style="border: 1px solid blue;background: yellow"><![CDATA[
   <ul>
      <li>Native browser content</li>
   </ul>
]]></html>
<button label="change" onClick="l.setContent(&quot;Hi Update&quot;)"/>

注意,由于SPAN用于包围嵌入的HTML标签,下面的语句是错误的。

<html><![CDATA[
   <ul>
      <li> <!-- incorrect since <ul><li> is inside <span> -->
]]></html>

<textbox/>

<html><![CDATA[
      </li>
   </ul>
]]</html>

如果你需要直接产生嵌入的HTML标签,而不用SPAN包围,你可以使用native命名空间,如下所示。

使用Native 命名空间,表示ZUML页面内的XML元素会被直接送至浏览网而不会成为ZK组件。例如,

<n:ul xmlns:n="http://www.zkoss.org/2005/zk/native">
   <n:li>
   <textbox/>
   </n:li>
   <n:li>
   <textbox/>
   </n:li>
</n:ul>

会产生下面的HTML标签送至浏览器:

<ul>
   <li>
   <input id="z_a3_2"/>
   </li>
   <li>
   <input id="z_a3_5"/>
   </li>
</ul>

此处,<input>为由textbox产生的HTML标签。不同于上例中的textbox,ZK加载器并不会为每个ulli [45] 创建一个组件。而是,它们直接被送至客户端。当然,它们必须是被客户端可识别的。对于HTML浏览器,它们必须为合法的HTML标签。

由于与Native关联的元素会直接被送至客户端,所以它们不是ZK组件,且在客户端没有对应部分。优点是根据内存和处理事件来看都有更好的性能。而缺点是你不能够动态的改变它们。例如,下面的代码片断是错误的,因为没有名为x的组件。

<n:ul id="x" xmlns:n="http://www.zkoss.org/2005/zk/native"/>
<button label="add" onClick="new Li().setParent(x)"/>

若你想动态改变它们,则可以按如下章节描述的那样指定XHTML 命名空间。

使用Native输出另外的命名空间

若你想生成另一个命名空间至输出,则可以使用另一种格式作为Native命名空间的URI。

native:URI-of-another-namespace

例如,若你想直接输出SVG标签之客户端,则可以指定native:native:http://www.w3.org/2000/svg,如下。

<window>
   <svg width="100%" height="100%" version="1.1"
   xmlns="native:http://www.w3.org/2000/svg">
      <ellipse cx="240" cy="100" rx="220" ry="30" style="fill:purple"/>
   </svg>
</window>

那么,客户端接受到的内容如下:

<div id="z_lx_0c" z.type="zul.wnd.Wnd">
   <svg width="100%" height="100%" version="1.1"
   xmlns="http://www.w3.org/2000/svg">
      <ellipse cx="240" cy="100" rx="220" ry="30" style="fill:purple"/>
   </svg>
</div>

XHTML命名空间, http://www.w3.org/1999/xhtml

XHTML表示XHTML组件集,就像ZUL命名空间(http://www.zkoss.org/2005/zul)代表ZUL组件集一样。因此,使用XHTML命名空间指定的一个XML元素表示此组件的创建将会基于定义在XHTML组件集内的组件。例如,下面的代码基于XHTML组件集创建了一个ul实例:

<h:ul xmlns:h="http://www.w3.org/1999/xhtml">

换言之,ZK加载器将会在XHTML 组件集内寻找组件定义ul,然后基于它创建一个实例。

下面是一个更完整的例子。

<window title="mix HTML demo" xmlns:h="http://www.w3.org/1999/xhtml">
   <h:table border="1">
      <h:tr id="row1">
         <h:td>column 1</h:td>
         <h:td>
            <listbox id="list" mold="select">
               <listitem label="AA"/>
               <listitem label="BB"/>
            </listbox>
         </h:td>
      </h:tr>
   </h:table>
   <button label="add" onClick="new org.zkoss.zhtml.Td().append(row1)"/>
</window>

不同于html组件,ZK加载器会为存储在content属性内HTML标签创建ZK组件。优点是你可以动态的操作每个HTML标签,就像在上面例子中描述的那样(add按钮)。缺点是需要花费更长的处理事件及更多的空间来维护。

[提示]: 不同于XHTML命名空间,Native并不代表另一种组件集。它只是一个保留的命名空间,用于告诉ZK加载器将它们直接送至客户端,以取得更好的性能。

include组件

include组件用于包含由另一个servlet 产生的输出。servlet可以是任何页面,包括JSF,JSP,甚至另一个ZUML页面。

<window title="include demo" border="normal" width="300px">
   Hello, World!
   <include src="/userguide/misc/includedHello.zul"/>
   <include src="/html/frag.html"/>
</window>

就像所有的其它属性,你可以在运行时动态的改变src属性包括来自于不同servlet的输出。

若被包括的输出是另一个ZUML,开发人员被允许访问此ZUML的组件,就好像它们是包含(containing)页面的一部分。

将值传递至包含页面

有两种方式将值传递至包含页面。一,你可以使用查询字符串。

<include src="mypage?some=something"/>

然后,在包含页面内,你可以使用ExecutionServletRequest接口的getParameter方法来访问它们。在EL表达式(包含页面内的)中,你可以使用param变量来访问它们。但是,使用查询字符串,你仅能传递字符串类型的值。

${param.some}

另一种方式,你可以利用setDynamicProperty方法所谓的动态属性,或者ZUL内的一个动态属性来传递任意值,如下:

<include src="mypage" some="something" another="${expr}"/>

使用动态属性,你可以传递非字符串类型的值。在包含页面内,可以使用ExecutionServletRequest接口的getAttribute方法来访问它们。在EL表达式(包含页面内的)中,你可以使用requestScope变量来访问它们。

${requestScope.some}

包含ZUML页面

如果include组件被用于包含一个ZUML页面,那么被包含的页面会成为桌面的一部分。但是,直到请求被完全处理被包含页面才会可见。换言之,仅当下列的事件被用户或计时器(timer)触发时被包含页面才会可见。

理由是include组件到页面响应阶段[46](the Rendering phase)才会包含一个页面。另外zscript 发生在组件创建阶段(the Component Creation phase), onCreate 发生在事件处理阶段(the Event Processing Phase)。它们都在包含前执行。

<window onCreate="desktop.getPages()"> <!-- the included page not available -->
   <include src="/my.zul"/>
   <zscript>
      desktop.getPages(); //the included page not available yet
   </zscript>
   <button label="Hit" onClick="desktop.getPages()"/>
      <!-- Yes, the included page is available when onClick is received -->
</window>

若你想浏览被包含页面的组件,宏(macro)组件通常是更好的选择。参考ZK用户界面标记语言一章中宏组件一节。

style组件

style组件被用于在ZUML页面中指定CSS样式。最简单的格式如下。

<style>
.blue {
color: white; background-color: blue;
}
</style>
<button label="OK" sclass="blue"/>

提示:为整个应用程序配置样式表,可以在zk.xm内指定theme-uri,参考国际化一章中主题一节或the Developer's Reference中的附录B(Appendix B) 获取细节。 为一中语言配置样式表,可以使用语言插件(language addon),参考 the Component Development Guide。

有时将所有的CSS定义放在一个单独的文件中是更好的选择,例如my.css。然后,我们可以使用style组件来引用它,如下。

<style src="/my.css"/>

上面的语句实际下列的HTMl标签[47]送至服务器,所以指定的文件必须是可被浏览器访问的。

<link rel="stylesheet" href="/css/mystyles.css"/>

换言之,你不能指定"/WEB-INF/xx" " C:/xx/yy "

就像其它的URI,style接受"*"来加载浏览器和本地化(Locale dependent)样式表。参考国际化一章中浏览器和本地化URI一节获取细节。

script组件

script组件用于指定运行在浏览器的脚本代码。注意,不同于zscript,脚本代码运行在浏览器。通常由大多数浏览器支持的JavaScript编写。最简单的格式如下。

<script type="text/javascript">
function myfunc() {
   $e("${win.uuid}").style.backgroundColor = "blue";
}
</script>

如上所示,你可以在脚本代码内使用EL表达式 (${win.uuid})。

当然,你可以使用src属性引用额外的JavaScript文件,如下。

<script src="/js/super.js" type="text/javascript"/>

由于ZK应用程序运行在服务器端(使用你最喜欢的语言执行),开发人员很少需要使用JavaScript代码来执行。它们通常定制ZK客户端引擎的行为,或运行遗留下来的JavaScript库。

iframe组件

iframe组件使用HTML IFRAME标签将显示的一部分委托(delegate)给另一个URL。尽管外观看起来与include组件相似,但是iframe组件的概念及意义是不同的。

include组件包含的内容是整个HTML页面的片断。由于内容是HTML页面的一部分,所以也是桌面的一部分,你可以访问include组件内的任何组件。包含是在服务器进行的,浏览器并不知道。这意味着src属性指定的URL可以是任何内部资源。

iframe组件的内容是由浏览器加载的,作为一个单独的页面。由于是作为单独的页面被加载,所以内容的格式可以不同于HTML。例如,你可以嵌入一个PDF文件。

<iframe src="/my.pdf"/>
...other HTML content

提示: 默认没有边框。若想启用,使用style属性指定,例如, <iframe style="border:1px inset" src="http://www.zkoss.org"/>

当解释包含IFRAME的标签时,embedding是被浏览器处理的。这也暗示着URL必须为从浏览器可访问的资源。

就像imageaudio组件[48],你可以动态指定生成的内容。典型的例子是使用JasperReport[49]生成一个PDF报告,以二进制数组或流格式,然后将结果包装成org.zkoss.util.media.AMedia类传递给iframe组件。

在下面的例子中,我们说明,你可以使用iframe嵌入任何内容,只要客户端支持内容的格式。

<window title="iframe demo" border="normal">
   <iframe id="iframe" width="95%"/>
   <separator bar="true"/>
   <button label="Upload">
      <attribute name="onClick">{
         Object media = Fileupload.get();
         if (media != null)
            iframe.setContent(media);
      }</attribute>
   </button>
</window>

用户上传一个Microsoft PowerPoint文件 ,这张图片描述了上传后的外观。

onURIChange事件

当用户操作iframe组件指向另一个URL(或bookmark签)时,org.zkoss.zk.ui.event.URIEvent类的一个对象会被发送至iframe组件。这个事件通常被用于标记(bookmark)iframe组件的状态,这样之后正确的内容会被修复(be restored)。

与其他技术的整合

iframe组件包含一个非ZK页面,则onURIChange事件不会被发送。例如,若包含一个PDF页面,此事件就不会被发送。

另一方面,如果你使用了其它技术将ZK页面置于一个iframe内,可以编写一个叫做onIframeChange的JavaScript方法监视URL。

//Part of your, say, PHP page
<script type="text/script">
function onIframeChange(uuid, url) {
    do_whatever_you_need_in_the_technology_you_use(uuid, url);
}
</script>

这里uuid是你使用document.getElementById获取的元素的ID,urliframe要浏览的一个新URL。注意,url包含上下文路径(context path),而URIEvent.getURI()不包含。



[43] html元素内的文本实际上是由html组件的content属性赋值的(而不是成为一个子标签)。

[44] 若你不熟悉XML, 参考ZK用户界面标记语言一章中XML一节。

[45] ZK实际上创建了一个特殊的组件来表示尽可能多的使用Native命名空间的XML元素。

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

[47] 实际的结果取决于Web应用程序的配置。

[48] 在许多方面,iframe类似于imageaudio。你可以将iframe当成一个可以包含任意内容的组件。

[49] http://jasperreports.sourceforge.net