跳转到内容

ZK/操作指南/概念与技巧

来自 Wikibooks,开放世界中的开放书籍

概念与技巧

[编辑 | 编辑源代码]

参数和事件监听器

[编辑 | 编辑源代码]

使用 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 等)
  • 如果文本框包含在一个单元格中,用户就无法选择其内容。

为什么在 BeanShell 中访问 value 属性时使用 alert 而不是错误框

[编辑 | 编辑源代码]

在下面的代码片段中,没有显示错误框。相反,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 会拉伸框。 变通方案

更改或自定义 FCKeditor 中的工具栏

[编辑 | 编辑源代码]

自 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 中看到您修改后的工具栏集。

如何在启动时打开 treeitem

[编辑 | 编辑源代码]

请尝试使用最新版本作为变通方案。

...

 
</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>


如何以编程方式创建一个带有 onClick zscript 的按钮?

[编辑 | 编辑源代码]

此代码不适用于 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?

[编辑 | 编辑源代码]

重要的是要注意,您用 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 变量值传递给 ZK 服务器

[编辑 | 编辑源代码]

有时我们需要编写一些浏览器端 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' 中使用 'self' 事件处理程序

[编辑 | 编辑源代码]

使用 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>




IE 相对定位 DIV 的溢出滚动

[编辑 | 编辑源代码]

溢出错误有很好的记录,并且存在于 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>

如何禁用 ZK 的进度条

[编辑 | 编辑源代码]

将以下代码添加到您的 zul 页面中。

<script type="text/javascript"><![CDATA[
window.Boot_progressbox = function (){}
]]></script>

如何在 zul 中不使用 zscript 访问类的静态成员字段

[编辑 | 编辑源代码]

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

[编辑 | 编辑源代码]

Firebug 被认为是降低 Javascript 性能的原因。这是一种检测用户是否启用 Firebug 的方法。这是一段 Javascript 代码。

  if(window.console && window.console.firebug){
      // Do something Javascript code.
  }

如何在将 ZK 和 JSP 集成时解决 IE6&7 中 CSS 未加载的问题。

[编辑 | 编辑源代码]

据我所知,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”中,但我认为我会把它放到论坛中,这样如果有人搜索“如何将参数传递给宏”,它就会出现。

华夏公益教科书