用 zul 快速制作雏形系统

在软件开发过程中,最不确定的因素是「需求」。因为通常要做的系统是没人用过的新系统,常常使用者没看到系统前也说不清楚自己要什麽,可能一开始说要个「发光的灯管加握把」(这什麽?),等你做给他的时候,他说他想要的是「光剑」...这种落差越晚发现,修改成本就越大。为了及早发现这种落差,开发者会用各种方式去逼出真实的需求,包括写规格书、画 wireframe、送小礼物(?)等...

制作雏形系统是一种好方法,因为使用者可以实际操作模拟的页面,较能得到接近真实需求的回馈,但是如果制作雏形系统要用另一套语言或方法,成本太高,未必值得。

用 zscript 内嵌 Java 程序码

zul 中的 <zscript> 让你可以内嵌 Java 程序码在 zul ,快速制作可执行的雏形系统,待使用者确认後,继续以该 zul 页面为基础扩增成为上线系统。

宣告变数

可用来塞样本资料。

<zscript><![CDATA[
String force = "愿原力与你同在";
]]></zscript>

执行 java 程序片段

可用来制造样本使用者。

<zscript><![CDATA[
Sessions.getCurrent().setAttribute("user", "天行者路克");
]]></zscript>

可以直接实作事件倾听器

直接把 java code 写在事件属性值中,就会被执行。

<button onClick='Messagebox.show("资料已送出")' label="送出"/>

注意使用 java 字串时,因为需要用双引号,因此属性值外层要用单引号。

定义 method

可以用来模拟功能。

    <zscript><![CDATA[
public void costaRicaBlessing(){
    Messagebox.show("pura vida");
}
]]></zscript>
    <button onClick='costaRicaBlessing()' label="哥斯大黎加的祝福"/>

用 ID 操作元件

元件的 ID 就是参照到元件物件的变数名称,可拿来呼叫元件 API:

<intbox id="box"/>
<zscript><![CDATA[
box.setValue(18);
]]>
</zscript>
  • 要注意顺序就跟写程序一样,元件定义要在前(宣告变数),呼叫方法必须要写在元件之後

以上这些就足以让你做出一个简单的可互动的雏形系统。

不过 zscript 是牺牲效能来达到 runtime 编译 java 的效果,因此不建议在生产环境使用。为了避免不小心误用,你可以设定关闭 (The disable-zscript Element),如果有人用了会立即丢出例外,可以及早发现。

支援 EL 3.0(Expression Language)

用过 JSP 的应该都会知道 EL,是一个简洁的存取 server-side 物件的语言,zul 也支援几近相同的语法,也有许多可直接使用的隐含物件。

EL变数可存取的物件

  • 定义在 中的变数
  • ZK 元件
  • 隐含物件
  • scope attributes

定义在<zscript> 中的变数可直接以变数名称存取:

<zscript><![CDATA[
     Date now = new Date();
]]></zscript>
<datebox value="${now}"/>

隐含变数跟 id 都可存取元件:

<window title="EL范例">
    <textbox id="tb" value="${self.parent.title}"/>
    ${tb.value}
</window>
  • self 是预先宣告的隐含物件,只能在元件的 attribute value 中使用,代表该元件自己,上例中 self 代表 Textbox 物件,${self.parent.title} 的结果就是其父元件的 title,也就是 EL范例
  • tb, Textbox 的 ID,在 EL 可用来存取 Textbox 物件的参照,因此 ${tb.value} 等同呼叫 Textbox.getValue(),结果也是EL范例
<button label="Enter" if="${not empty param.edit}"/>

解析 scope attribute 顺序

这里的 scope 指得是 Java EE scopes,你可把任何物件存入这些 scope 的 attribute 中,用来分享给同样 scope 的其他物件。除了 Java EE 本身定义的几种 scope 之外,ZK 也另外定义两种 scope。

component scope: 这应该很容易理解,元件存在时,存入的 attribute 就存在,元件消灭就跟着消灭。

desktop scope: 这是 ZK 创造的范畴,因为每个浏览器 tab 的 JavaScript widget 都是独立,但是却又同属一个 session ,因此 ZK 需要一个 scope 来区分同一个 session 下两个不同 tab 中的元件,因此创造了 desktop,你可以把它视为对应到一个浏览器 tab,一个 desktop 存放着整个页面的元件树,当 tab 关闭时,desktop 就消灭,或浏览器重载页面 (reload) 也会创造一个新 desktop。因此存在 desktop attribute 中的资料,其下的所有元件都能存取到。

当一个 EL 变数在被解析为 scope attribute 时,ZK 会从小的 scope 依次搜寻到大的 scope 直到找到为止,顺序如下:

  1. request/execution (Java EE)
  2. component (ZK)
  3. desktop (ZK)
  4. session (Java EE)
  5. application (Java EE)

HTTP request/AJAX request 在 ZK 内部都被封装成 Execution 物件,因此在 ZK文件中多半以 execution 来指称 request。

若是完全找不到,也不会显示任何错误,就是不显示任何文字在页面上。因为这个特性,若是两个 attribute 有相同的 key 存在不同的 scope 中,小 scope 的 attribute 会先被找到就不会再往大 scope 找了,要注意这种「遮蔽」现象。

    <div id="parent">
        <zscript><![CDATA[
//the smaller scope (lower one) can shadow the upper one
application.setAttribute("myname", "in application");
session.setAttribute("myname", "in session");
desktop.setAttribute("myname", "in desktop");
page.setAttribute("myname", "in page");
parent.setAttribute("myname", "in component");
execution.setAttribute("myname", "in execution");
]]></zscript>
        解析结果:
        <label style="font-weight: bold" value="${myname}"/>
    </div>
  • 上面这个范例,因为所有的 attribute key 值相同,你若依次移除较小 scope 中的 attribute,ZK 才会解析出较大 scope 中的值

串接字串

${'Hi, ' += firstname += ' ' += lastname}

创建时估值

ZK 根据 EL 表达式从目标物件取出值的过程我们称「估值 (evaluation)」,ZK 只在创建元件的时後会做 EL 估值,之後如果元件只是透过 ajax 更新资料或外观,ZK 不会再重估值一次。何时是元件创建时呢?

  • 浏览器访问某个 zul 时,ZK 根据 zul 内容创建所有的元件
  • 使用者使浏览器重新载入整个页面
  • 透过 API 创建元件,或是透过范本插入(之後会提到)重建元件时

更多细节请参考 ZUML_Reference/EL_Expressions

混用 HTML

在做雏形页面时,可能部分页面需求没有对应的元件可用,需要自行以 HTML 设计,因此总是有需要混用 HTML tag 的时候,这时你需要要先宣告 namespace并指定前缀,并在每个 HTML tag 前方加上指定前缀:

<zk xmlns:h="native">
<h:h1>混用 HTML</h:h1>

以上例来说,ZK 就知道 <h:h1>是 HTML tag 而不是 ZK 元件。

如果你要贴上大量 HTML tag,例如可能是设计师设计好的 HTML 页面,你可以在某一个 tag 宣告 HTML 是预设的 namespace,这样ZK 就会认定其下方的都是 HTML tag,而不需另外加前缀:

<h:div xmlns="native">
    <h2>预设都是 HTML tag</h2>
    <span>不需要加前缀</span>
</h:div>

更多细节请参考 ZUML Reference/ZUML/Namespaces


<<:  Day 07. 安装 Zabbix Agent 在 Windows 10

>>:  Day06 UIKit 05 - 纯代码编写 Code

装置在Windows上未就绪错误如何重新连接您的磁碟机

装置未就绪是Windows作业系统一个常见的错误。在Windows OS的所有版本中均会看到此错误。...

[前端暴龙机,Vue2.x 进化 Vue3 ] Day21. 『小专题◕ᴥ◕』 Vue 旅游小帮手(二)

今天继续来增加功能,并再取得另一批资料来使用 目标四,再加入旅馆 API 有了景点,再来解决住的部份...

Day05 - Python基本语法 Part 2,关於「集合」

接续昨天的基本语法,今天将主要集中在「集合」的内容整理。 范例程序主要来自於W3Schools。 集...

Day 6 ELK Stack on k8s 介绍

2021 铁人赛 DAY6 在上篇我们利用Prometheus捞取丛集内资源使用率的metric,再...

Day01 前言

从小到大看了上万篇的文章,绝大部分的文章开头肯定是少不了跟读者打招呼的。 大家安安,我这次报名的题目...