ZK/操作指南/概念与技巧
使用 Execution.getParameter() 或 EL 中的 ${param[key]} 访问参数很简单,如下所示。
<button label="${param['what']}"/>
但是,您无法在事件监听器中访问它。例如,在下面的示例中,按钮的标签一旦按下就会变为空。
<button label="${param['what']}" onClick="doIt()"/> <zscript> void doIt() { self.label= Executions.getCurrent().getParameter("what"); }
为什么?
参数映射仅在页面评估时可用。而且,当用户点击按钮时,会生成另一个 URL,之前的参数就消失了。
解决方案
<button label="${param['what']}" onClick="doIt()"/> <zscript> tmp = Executions.getCurrent().getParameter("what"); void doIt() { self.label= tmp; }
网格 和 列表框 都支持多列和多行。它们看起来很像。应该使用哪一个?列表框和网格中也使用组合框。onopen() 用于在运行时在列表框和组合框中创建数据库记录;
- 主要用途:表格形式的数据呈现。
- 每个单元格可能彼此大不相同
- 要实现选择,开发人员必须为每一行添加一个复选框。没有简单的方法来实现单选(使用单选按钮)。
- 主要用途:可选择的数据
- 选择直接支持(通过使用 getSelectedItem 等)
- 如果文本框包含在一个单元格中,用户就无法选择其内容。
在下面的代码片段中,没有显示错误框。相反,ZK 将其视为编程错误(通过使用 JavaScript 的 alert 显示异常)
<zk> <textbox id="box" constraint="no empty"/> <button label="cause validation error" onClick="alert(box.value)"/> </zk>
为什么?BeanShell 拦截所有异常,并使用它自己的异常来表示它们。因此,ZK 不知道它实际上是由 WrongValueException 引起的。
解决方案:使用 getValue() 和 setValue() 而不是直接访问属性名。
<zk> <textbox id="box" constraint="no empty"/> <button label="cause validation error" onClick="alert(box.getValue())"/> </zk>
如果您有一个具有许多(例如 1,000,000 个)项目的列表框,则不能使用列表框的内部分页机制(换句话说,您不能设置 '分页' 模具)。原因是内部分页机制将创建与项目数量一样多的列表项。
由分页控制的列表框将始终显示从偏移量“页大小 * 活动页面计数”到“页大小 * (活动页面计数 + 1)”的列表项。因此,您必须 *不* 将列表项数量与实际元素数量不匹配的列表框与分页元素关联起来。换句话说,不要让列表框成为分页元素的被控对象。相反,创建一个单独的分页元素,如下所示
<vbox> <listbox id="box" /> <paging id="paging" /> </vbox>
将实际项目的数量设置为分页控制器的“totalSize”
paging.setTotalSize(1000000);
现在,您必须拦截“onPaging”事件
paging.addEventListener("onPaging", new EventListener() { public void onEvent(Event e) { PagingEvent pe = (PagingEvent)e; int desiredPage = pe.getActivePage(); // now retrieve items desiredPage * pagesize .. (desiredPage+1) * pagesize // and assign their content to listitem 0 .. pagesize } });
因此,始终只有与当前显示的列表项一样多的列表项。
请注意,此技术的缺点是您必须将分页控制器放置在列表框之外。您不能将此分页控制器添加到列表框,因为列表框会检查是否添加了最多一个 org.zkoss.zul.Paging 实例的子项,以防它与内部分页组件发生冲突。第二个缺点是您不能使用 “box.getPageSize()” 方法,该方法依赖于内部分页。您必须改为使用 “paging.getPageSize()”。另外,如果您使用此技术,请确保 *不* 调用 box.setPaginal(paging)。
在 ZK 中使用带百分比的 width= 属性需要小心,因为它的含义与其他框架不同。一方面,ZK 努力成为一个与浏览器无关的框架。另一方面,在渲染 HTML 时,ZK 经常将 width= 属性传递给它使用的 HTML 元素,这会导致意想不到的效果。原因是,传递 width= 属性的 HTML 元素形成的层次结构不同于它们起源的 ZUL 元素。
为了理解这一点,请考虑以下场景
<hbox width="100%"> <div width="50%" style="background-color: blue;"> Left </div> <div width="50%" style="background-color: green;"> Right </div> </hbox>
此处,目的是让父 hbox 占用其父元素(可能是窗口)的 100%,让每个 'div' 子元素占用其父元素的 50%。在 CSS 中,[W3C], width 属性指的是包含块。
但是,ZK 粗略地将上述内容渲染为以下内容
<table width="100%"> <tr> <td> <div style="width:50%"> Left </div> </td> <td> <div style="width:50%"> Right </div> </td> </tr> </table>
熟悉 CSS 的用户会注意到,width:50% 属性现在不再是指用于渲染 'hbox' 的 'table' 元素,而是指 ZK 插入的 'td' 元素!'td' 元素的默认宽度为表格的 50%(因为有两个 'td' 元素),因此 'div' 元素的实际宽度为表格的 25%。很明显,为了正确使用 width=,必须了解 ZK 如何在 ZUL 和 HTML 之间进行转换(与 ZK 开发人员的意图相反)。
为了解决这个问题,ZK 为框元素提供了“widths”属性。'widths' 属性允许将 'width:' 属性分配给构成框的 'td' 元素。为了达到预期效果,您必须使用
<hbox widths="50%,50%" width="100%"> <div width="100%" style="background-color: blue;"> Left </div> <div width="100%" style="background-color: green;"> Right </div> </hbox>
它将被渲染为
<table width="100%"> <tr> <td style="width:50%"> <div style="width:100%"> Left </div> </td> <td style="width:50%"> <div style="width:100%"> Right </div> </td> </tr> </table>
因此,表格占据其父元素的 100%,每个 'td' 元素占据表格宽度的 50%,每个 'td' 中的 'div' 元素占据整个空间 (100%)。
属性 'widths' 为盒子提供了一种变通方案,但不幸的是,它没有提供通用的解决方案。通过将 'width=' 属性传递给 HTML 元素,ZK 使渲染依赖于所使用的浏览器,从而将 ZK 用户暴露于所有与宽度相关的渲染错误。此外,这些错误很难调试,因为它们需要 ZK 用户了解 ZK 的渲染过程,才能开始解决导致这些错误的浏览器特性。
例如,将宽度指定为 100% 给 <textbox> 将导致将样式 "width:100%" 应用于 <input type="text"> 元素,这会触发不同浏览器的错误 - 例如,当放置在文本框中的值大于框时,IE 会忽略宽度限制。在这种情况下,IE 会拉伸框。 变通方案
自 2007 年 3 月 13 日起,FCKeditor 支持新的方法 setCustomConfigurationsPath(String url),您可以指定自定义配置 .js 文件的 url。您不再需要修改 fckez.jar 中的 fckconfig.js。有关可自定义内容的详细信息,请参阅 FCKeditor 配置文件
以下是如何为 FCKeditor 创建一个新的工具栏集。
1. 创建一个 JavaScript .js 自定义配置文件,例如,将 myconfig.js 放置在您的 Web 路径中的某个位置。为了便于描述,本示例将将其放在根路径下;即 "/myconfig.js"。
2. 在文件中创建一个新的工具栏集 "Simple" (myconfig.js)。例如:
FCKConfig.ToolbarSets["Simple"] = [ ['Bold','Italic','Underline','StrikeThrough','-','TextColor','BGColor'] ];
3. 要使用此 /myconfig.js,您必须在 <fckeditor> 标签中指定它
<fckeditor customConfigurationsPath="/myconfig.js" toolbarSet="Simple"/>
或通过 Java 方法
FCKeditor myFCKeditor = new FCKeditor(); myFCKeditor.setCustomConfigurationsPath("/myconfig.js"); myFCKeditor.setToolbarSet("Simple");
4. 好了。您完成了。
以下是需要您修改 fckez.jar 中的 fckconfig.js 的旧方法
要更改 FCKeditor 中的工具栏或创建一个新的工具栏,必须修改 fckez.jar 文件中的 fckconfig.js 文件。
1. 在出现任何错误时,备份 fckez.jar 文件。
2. 将 fckez.jar 文件重命名为 fckez.zip (jar 文件只是 zip 文件,所以这可以正常工作)
3. 将 fckez.zip 文件解压缩到某个位置。建议创建一个新目录。
4. 找到 fckconfig.js 并打开它进行编辑。它应该位于 \web\js\ext\FCKeditor\fckconfig.js
5. 找到工具栏部分。以下是基本部分。
FCKConfig.ToolbarSets["Basic"] = [ ['Bold','Italic','-','OrderedList','UnorderedList','-','Link','Unlink','-','About'] ] ;
6. 要创建一个新的 ToolbarSet,请复制 FCKConfig.ToolbarSets... 之间的全部内容到分号 ;
7. 将其粘贴到分号之后,并更改名称。
FCKConfig.ToolbarSets["Simple"] = [ ['Bold','Italic','-','OrderedList','UnorderedList','-','Link','Unlink','-','About'] ] ;
8. 根据需要更改 Toolset。按钮在单引号中定义。'-' 是工具栏分隔符。让我们删除链接和取消链接按钮。
FCKConfig.ToolbarSets["Simple"] = [ ['Bold','Italic','-','OrderedList','UnorderedList','-','About'] ] ;
9. 保存文件并退出编辑器程序。
10. 向上导航目录树,直到您到达 web 文件夹级别,并将整个树放入 zip 文件中。(这将保留修改后的文件在目录结构中的位置。)
11. 将 zip 文件重命名回 fckez.jar,并将 jar 文件放入与其他 zk jar 文件相同的 tomcat shared/lib 目录中。
12. 更改您在 zk 应用程序中调用 FCKeditor 的代码,以使用 'Simple' 工具栏集。
FCKeditor myFCKeditor = new FCKeditor(); myFCKeditor.setToolbarSet("Simple");
13. 启动 Tomcat,并使用浏览器查看您的应用程序。您应该在 FCKeditor 中看到您修改后的工具栏集。
请尝试使用最新版本作为变通方案。
...
</treecols> </tree> <zscript> int[] path ={0}; tree.renderItemByPath(path); int[] path ={1}; tree.renderItemByPath(path); </zscript>
... 另外,请参考 javadoc- treemodel 获取有关路径的详细信息,
请随时在 sourceforge 上的 ZK 论坛上发布更多问题
由于某些规范变更,3.0.3 之后,请参考以下内容:...
</treecols> </tree> <zscript> int[] path ={0.0}; tree.renderItemByPath(path); int[] path ={1.0}; tree.renderItemByPath(path); </zscript>
... 这是一个用来练习的演示代码
<?xml version="1.0" encoding="UTF-8"?> <zk xmlns="http://www.zkoss.org/2005/zul"> <window title="Dynamically Change by Model"> <zscript><![CDATA[ class MySimpleTreeNode extends SimpleTreeNode { private String myData = null; public MySimpleTreeNode(String data, List children) { super(data, children); myData = data.toString(); } public String toString() { return "Node: " + myData; } public void append(String data) { myData = myData + data; } public Object getData() { return myData; } } List aChildren = new ArrayList(); List empty = new ArrayList(); List a2Children = new ArrayList(); MySimpleTreeNode a20 = new MySimpleTreeNode("A2-0", empty); MySimpleTreeNode a21 = new MySimpleTreeNode("A2-1", empty); MySimpleTreeNode a22 = new MySimpleTreeNode("A2-2", empty); a2Children.add(a20); a2Children.add(a21); a2Children.add(a22); MySimpleTreeNode a0 = new MySimpleTreeNode("A0", empty); MySimpleTreeNode a1 = new MySimpleTreeNode("A1", empty); MySimpleTreeNode a2 = new MySimpleTreeNode("A2", a2Children); aChildren.add(a0); aChildren.add(a1); aChildren.add(a2); List children = new ArrayList(); MySimpleTreeNode a = new MySimpleTreeNode("A", aChildren); children.add(a); List bbChildren = new ArrayList(); MySimpleTreeNode b00 = new MySimpleTreeNode("B0-0", empty); bbChildren.add(b00); List bChildren = new ArrayList(); MySimpleTreeNode b0 = new MySimpleTreeNode("B0", bbChildren); MySimpleTreeNode b1 = new MySimpleTreeNode("B1", empty); MySimpleTreeNode b2 = new MySimpleTreeNode("B2", empty); bChildren.add(b0); bChildren.add(b1); bChildren.add(b2); MySimpleTreeNode b = new MySimpleTreeNode("B", bChildren); children.add(b); List rList = new ArrayList(); rList.add(a); rList.add(b); MySimpleTreeNode r = new MySimpleTreeNode("Root", rList); List rootList = new ArrayList(); rootList.add(r); MySimpleTreeNode root = new MySimpleTreeNode("Root", rootList); SimpleTreeModel stm = new SimpleTreeModel(root); public void renderByPath(Object obj){ int[] result = stm.getPath(root,obj); for(int i =0; i < result.length;i++) { System.out.println(result[i]); } tree.renderItemByPath(result); } public void renderByPathMul(){ int l = tree.getTreechildren().getChildren().size(); System.out.println(l); for(int i=0; i<l; i++) { int[] path ={0,i}; tree.renderItemByPath(path); } } ]]></zscript> <vbox> <tree model="${stm}" id="tree" width="700PX"> </tree> <hbox> <button label='renderByPath A2' onClick='renderByPath(a2)' /> <button label='renderByPath B0-0' onClick='renderByPath(b00)' /> <button label='renderByPath A2-1' onClick='renderByPath(a21)' /> <button label='renderByPath Root' onClick='renderByPath(r)' /> <button label='renderByPath A' onClick='renderByPath(a)' /> </hbox> </vbox> </window> </zk>
此代码不适用于 ZK 3.5.1!
点击演示页面上的 "Try Me!" 按钮查看源代码面板。剪切并粘贴以下示例,然后再次点击 "Try Me!" 加载示例。然后点击按钮查看代码运行效果。
<window title="My First Window" border="normal" width="200px"> <vbox id="myVbox"> <button label="create new button"> <attribute name="onClick"> <![CDATA[ deleteButton = new Button("Click me!"); // Store an arbitary piece of data in my button (e.g. some data primary key of the some object to delete) deleteButton.setAttribute("myDeleteButtonAttribute", "mary had a little lamb"); cond = new org.zkoss.zk.ui.util.Condition(){ boolean isEffective(Component comp) {return true;} boolean isEffective(Page page){return true;} }; // here the script just does a serverside alert showing the silly text but you could call a // business delegate function to delete something from the database. zscript = new org.zkoss.zk.ui.metainfo.ZScript("java", "alert(self.getAttribute(\"myDeleteButtonAttribute\"));", cond); eventHandler = new org.zkoss.zk.ui.metainfo.EventHandler( zscript, cond); deleteButton.addEventHandler("onClick", eventHandler); myVbox.appendChild(deleteButton); ]]> </attribute> </button> </vbox> </window>
重要的是要注意,您用 zscript 编写的事件处理程序和函数在服务器上运行,而不是在浏览器中运行。有一个名为 "客户端操作" 的功能,您可以让浏览器并行运行一些 JavaScript 函数以响应您的服务器端事件处理程序。客户端操作非常适合浏览器的图形效果。在浏览器中运行的 JavaScript 客户端操作无法访问您的服务器端业务对象、整个 Java JDK 和包含丰富 XUL 对象的服务器端 ZK 桌面。服务器端 zscript 可以直接访问所有这些内容,您可以使用包括 JavaScript 在内的多种语言。
此代码展示了如何在服务器端事件 zscript 处理程序中选择使用 JavaScript 而不是解释型 Java (BeanShell)
<?page zscript-language="javascript"?> <window> <zscript> // this is a JavaScript function that creates a JavaScript object literal // on the server and runs the server-side alert function function hello(){ var now = new java.util.Date(); // you can script pure Java objects! var myMessage = {msg:'hello world '+now}; // pure JavaScript alert(myMessage.msg); // JavaScript calling a Java method // Rhino = JavaScript on Java (http://www.mozilla.org/rhino/doc.html) } </zscript> <button label="Say hello world"> <attribute name="onClick"> hello(); </attribute> </button> </window>
您可以在 zkoss.org 网站的演示页面上运行该示例。只需按下 "Try Me!" 按钮显示编辑器,粘贴示例,然后再次按下 "Try Me!" 加载示例,然后按下 "Say hello world" 按钮查看其运行效果。
您不能期望做的事情是写类似于
window.setTimeout("alert('hello');", 1000);
在服务器端 JavaScript 函数中。为什么?因为 'window' 只是浏览器 JavaScript 运行时中的一个隐式对象引用。由于事件处理程序在服务器上运行,因此您无法直接访问浏览器中的对象。服务器端 ZK 中没有名为 'window' 的隐式对象引用。我们可以给 xul 窗口标签和 id 赋予 "window",然后我们可以对其进行脚本化。将以下示例剪切并粘贴到 zkoss.org 演示的 "Try Me!" 代码编辑器中,然后再次点击 "Try Me!" 加载它
<?page zscript-language="javascript"?> <window id="window" title="This is my window title"> <zscript> // this is a JavaScript function that manipulates the // desktop object that is assigned the ID "window" function changeWindowTitle(title){ window.title = title; } </zscript> <label value="New title:"/> <textbox id="new_title" value="edit me..."/> <button label="Change the window title."> <attribute name="onClick"> changeWindowTitle(new_title.value); </attribute> </button> </window>
我们在那里给窗口对象赋予了 'window' 的 ID,以便我们可以在 zscript 中通过该名称引用它并更改其标题。我们仍然不能调用 "window.setTimeout()",因为 ZK Window 组件上没有名为 setTimeout 的方法。ZKOSS 网站上的 JavaDoc 查看 Window 和其他组件有哪些方法。我们在上一个示例中隐式地使用了 setTitle,当时我们在 zscript 中为 window.title 设置了一个新值。
人们一直使用的一个浏览器方法是
document.getElementById('some_id');
这不会奏效,因为 'document' 是浏览器中的一个隐式对象,它不存在于服务器端 ZK 中。但不要失望!ZK 除了 76 种 XUL 对象类型外,还有 86 种不同类型的 XHTML 对象。它将在服务器上构建一个混合的 XHTML 和 XUL "DOM",称为桌面。以下示例使用 JavaScript zscript 操作一些 XHTML
<?page zscript-language="javascript"?> <zk xmlns:h="http://www.w3.org/1999/xhtml"> <window id="window"> <zscript> function changeParagraph(){ // this script code changes the xhtml objects on the server myParagraph.children.get(1).value = 'goodbye world'; } </zscript> <!-- The following are XHTML elements. If you don't like the prefix 'h' see the DevGuide about how to set the default namespace to be html. --> <h:p id="myParagraph"> <h:img src="https://wikibooks.cn/skins-1.5/common/images/button_bold.png"></h:img> hello world <!-- "hello world" is in an implicit Text element --> </h:p> <!-- This is a XUL button that has an onClick that changes an XHTML element --> <button label="Change hello to goodbye"> <attribute name="onClick"> changeParagraph(); </attribute> </button> </window> </zk>
您无法更改 XHTML IMG 元素的 src 属性。请改用 ZUL IMAGE 元素。同样,如果您想设置 IFRAME 的源,请使用 ZUL 元素,而不是 XHTML 元素。为什么?因为这样,当您在 zscript 中直接访问您的业务逻辑后更改它们在服务器上的状态时,ZK 将自动更新浏览器中相应的 DOM 元素。ZUL 元素已记录在 此处,ZHTML 元素已记录在 此处。
有时我们需要编写一些浏览器端 JavaScript 函数来完成某些操作。我们可以使用 CSA (客户端操作) 来触发操作,没有问题。但是,JavaScript 执行完成后,我们可能需要从 zscript 函数 (在服务器端运行的代码) 中访问 JavaScript 变量的值。这是一个实现此目的的技巧。基本上,我们准备一个 "代理" 文本框。将 JavaScript 值复制到文本框的值并模拟 "onChange" 事件,以便真正将值发送回服务器。以下是示例代码
<zk> <script type="text/JavaScript"> <![CDATA[ function test(tbxsss) { var sssval = "Time: "+(new Date()); tbxsss.value = sssval; if (document.createEvent) { var evt = document.createEvent('HTMLEvents'); evt.initEvent( 'blur', false, false); tbxsss.dispatchEvent(evt); var evt2 = document.createEvent('HTMLEvents'); evt2.initEvent( 'change', false, false); tbxsss.dispatchEvent(evt2); } else if (document.createEventObject) { tbxsss.fireEvent('onblur'); tbxsss.fireEvent('onchange'); } } ]]> </script> <window id="win" title="My First Window" border="normal" width="200px"> <textbox id="sss" value="test" onChange="alert(self.getValue());" visible="false"/> <button id="btn" label="Invoke JS" action="onclick:test(#{sss})"/> </window> </zk>
点击按钮时,会执行 JavaScript 函数 test()。然后,它将新的字符串“abc”复制到文本框的值中,并模拟 onblur 和 onchange 事件。这将导致 ZK JavaScript 引擎将新值“abc”传递回服务器端,更新 Textbox 对象的值属性,并触发“onChange”ZK 事件。现在,您可以从这个“代理”文本框访问该值。如果您仔细阅读示例代码,您应该注意到文本框在浏览器中是“不可见”的(visible = “false”),因此它不会干扰您的布局。玩得开心!
使用 forEach 动态构建用户界面非常有用。如果您的 forEach 中有事件处理程序,您可以使用 'self' 来引用发生事件的组件。您也可以使用 'self' 从发生事件的组件开始遍历组件范围。
<window> <zscript><![CDATA[ /** * in a real application we would use something like * List iterateOverMe = sessionScope.get("searchResults"); */ String[][] iterateOverMe = { {"Fred","Flintstone"} ,{"Wilma","Flintstone"} ,{"Barney","Rubble"} ,{"Betty","Rubble"} }; void doRespondToClick(){ String message = "I am "+self.id; List people = self.parent.children; for( Iterator i = people.iterator(); i.hasNext(); ){ Object person = i.next(); if( person.id != self.id ) message += "\nI am next to "+person.id; } alert(message); } ]]></zscript> <vbox> <!-- Here I know that ${each} is a String[] so I pull out its first and second element. A more realistic example would be to access arbitrary getters on a POJO domain model object e.g. I could call: com.your.Person.getFirstName() simply by using: ${each.firstName} such that the label below would be defined as label="Click Me ${each.firstName} ${each.lastName}" --> <button forEach="${iterateOverMe}" id="${each[0]} ${each[1]}" label="Click Me ${each[0]} ${each[1]}" onClick="doRespondToClick()"/> </vbox> </window>
溢出错误有很好的记录,并且存在于 IE6 或 IE7 中。因此,在这种情况下,我们必须在外部标签中指定“position:relative”。例如,
<window title="tree demo" border="normal"> <div style="overflow:auto;position:relative" width="300px" height="100px"> <tree id="tree" width="90%" rows="5"> <treecols sizable="true"> <treecol label="Name" /> <treecol label="Description" /> </treecols> <treechildren> <treeitem> <treerow> <treecell label="Item 1" /> <treecell label="Item 1 description" /> </treerow> </treeitem> <treeitem> <treerow> <treecell label="Item 2" /> <treecell label="Item 2 description" /> </treerow> <treechildren> <treeitem> <treerow> <treecell label="Item 2.1" /> </treerow> <treechildren> <treeitem> <treerow> <treecell label="Item 2.1.1" /> </treerow> </treeitem> <treeitem> <treerow> <treecell label="Item 2.1.2" /> </treerow> </treeitem> </treechildren> </treeitem> <treeitem> <treerow> <treecell label="Item 2.2" /> <treecell label="Item 2.2 is something who cares" /> </treerow> </treeitem> </treechildren> </treeitem> <treeitem label="Item 3" /> </treechildren> </tree> </div> </window>
我们需要捕获 onFocus 事件来记录现在谁获得了焦点。例如,
<zk> <zscript> Component current; void changeFocus(Component t){ current = t; } </zscript> <window title="My First Window" border="normal" width="300px"> <hbox>Window 1 : <textbox id="First" onFocus="changeFocus(self)"/></hbox> </window> <window title="My Second Window" border="normal" width="300px"> <hbox>Window 2 : <textbox id="Second" onFocus="changeFocus(self)"/></hbox> </window> <window title="My Third Window" border="normal" width="300px"> <hbox>Window 3 : <textbox id="Third" onFocus="changeFocus(self)"/></hbox> </window> <window title="My Fourth Window" border="normal" width="300px"> <hbox>Window 4 : <textbox id="Fourth" onFocus="changeFocus(self)"/></hbox> </window> <button label="Show" onClick="alert(current.id)"/> </zk>
将以下代码添加到您的 zul 页面中。
<script type="text/javascript"><![CDATA[ window.Boot_progressbox = function (){} ]]></script>
ZUL 的 EL 支持标签库,因此我们可以编写一个 util 标签库函数来从 zul 访问静态成员字段。(或任何其他静态函数)
Note: ZK 3.0 introduced the xel-method directive to declare a static method directly in a ZUL page (without TLD). <?xel-method prefix="c" name="forName" class="java.lang.Class" signature="java.lang.Class forName(java.lang.String)"?> Use TLD as described below if you want to manage the declarations in a single TLD file (rather than scattering around ZUL files), or you want to be compatible with ZK 2.x.
步骤 1. 编写标签库,我将此字段放在 src/metainfo/tld/myutil.tld 中
<?xml version="1.0" encoding="ISO-8859-1" ?> <taglib> <uri>http://mytld/util</uri> <description> </description> <function> <name>sf</name> <function-class>mytld.Util</function-class> <function-signature> java.lang.String getStaticField(java.lang.String name) </function-signature> <description> </description> </function> </taglib>
步骤 2. 编写标签库配置,此文件必须放在 src/metainfo/tld/config.xml 中
<?xml version="1.0" encoding="UTF-8"?> <config> <version> <version-class>org.zkoss.zk.Version</version-class> <version-uid>3.0.1</version-uid> </version> <taglib> <taglib-uri>http://mytld/util</taglib-uri> <taglib-location>/metainfo/tld/myutil.tld</taglib-location> </taglib> </config>
步骤 3. 标签库实现
public class Util { static public String getStaticField(String name){ try{ int i = name.lastIndexOf("."); String field = name.substring(i+1,name.length()); name = name.substring(0,i); Class clz = Class.forName(name); Object obj = clz.getField(field).get(null); if(obj!=null){ return obj.toString(); } return null; }catch(Exception x){ throw new RuntimeException(x); } } }
步骤 4. 在 zul 中访问标签库。(sf 是在步骤 1 中声明的函数名称)
<?taglib uri="http://mytld/util" prefix="t" ?> <window id="${t:sf('mytld.CompIds.ID1')}" title="title"> <button label="click" onClick="alert(self.parent.id)"/> </window>
Firebug 被认为是降低 Javascript 性能的原因。这是一种检测用户是否启用 Firebug 的方法。这是一段 Javascript 代码。
if(window.console && window.console.firebug){ // Do something Javascript code. }
据我所知,ZK CSS 文件无法在 IE6&7 上的 JSP 中加载,因此您必须在 JSP 文件中添加以下页面定义。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ... //Your JSP content ...
如果您有一个宏组件,并且您在窗口中使用该宏,则以下内容显示了将参数传递给宏的确切语法(这在开发人员指南中,但没有实际示例)以及如何在宏中使用它们
这是宏组件
<hbox valign="center"> <button id="pmminusButton"/> <progressmeter width="${arg.width}" value="${arg.initialValue}" id="dhProgressMeter" /> <button id="pmplusButton"/> </hbox>
这是我窗口文件顶部的 include 语句,我在其中指定要传递的参数
<?component name="dhProgressMeter" inline="true" macro-uri="/macros/dhProgressMeter.zul" width="90px" initialValue="20" ?>
这里重要的内容是,我声明了两个要传递给宏组件的变量,“width”和“initialValue”。
在宏本身中,您可以看到我是使用 ${arg.width} 和 ${arg.initialValue} 获取这些参数的值的。
这很简单,我认为可以放到“how-to”中,但我认为我会把它放到论坛中,这样如果有人搜索“如何将参数传递给宏”,它就会出现。