Shadow Element:控制 UI 元件的元件

shadow element, 它的命名就透露出它不是个外显的 UI 元件,实际上它的确不会绘制出任何东西到浏览器上,只是在元件树上控制元件的生成与消灭,如同阴影般隐藏在元件背後的幕後操盘手。以下方的片段来说:

<div>
    <if test="${user.editable}">
        User Name: <textbox value="${user.name}"/>
        <forEach items="${user.phones}" var="phone">
            <label value="${phone.number}"/>
        </forEach>
    </if>
</div>

https://ithelp.ithome.com.tw/upload/images/20210929/20050621XYC97Ch6Cg.png

解析完 zul 之後会产生左边的元件树。

执行期时,会根据 <if> 中 EL 表达式算出来的结果来决定要不要生成其下的 <textbox> <label><forEach> 会根据 ${user.phones} 数量来决定要产生几个 。而 shadow 元件本身并不会产生对应的元件实体,浏览器端也不会绘制出任何 DOM 元素。

Shadow 元件共有以下这些:

  • <apply>: 范本插入,可以插入事先定义的范本或是 zul 档
  • <forEach>:走访集合物件来控制元件生成
  • <if>:条件判断,如果给定的 EL 结果为 true 就新建其包含的元件,如果为 false 就移除其包含的元件
  • <choose> <when> <otherwise>:条件判断,如同 java 中的 switch, case, default

在我们用 zul 建构画面时,有时会发现某些元件组合或是某个页面的区块重复出现,最直接的方式是「复制—贴上」,但更好的方式能够直接重用该片段。ZK 以往提供的方式是用 ,8.0 之後则可使用 shadow 元件 <apply>,效果更好。

比较

我推荐优先使用 <apply> ,理由如下:

  • <apply> 不会产生任何 DOM 元素
    <include> 会产生一层 <div>,有时候多一个 <div>会影响画面排版
  • <apply> 不会占用记忆体
    静态用法下不会占用记忆体,但 <include> 本身是 UI 元件,因此本身仍会占用记忆体
  • <apply> 不会产生 ID space。
    <include> 会产生一个 ID space,导致要 @Wire 元件时要 selector 语法较复杂
  • <apply> 可以接受档案路径或范本名称
    <include> 只能接受路径

<apply> 就如同 inline 的概念一样,由 ZK 把要引入的 zul 片段,由 zk 帮你动态的插入到目的页面上。

静态用法

如果填入字串值或是 EL,是属於静态用法,因为只在元件创建的时候估值,创建完之後服务器就不需要保留 <apply> 物件,因此 <apply> 本身不占记忆体:

<apply templateURI="customerDetails.zul" />

可透过 EL 来加上简单的判断逻辑:

<apply template="${currentUser.hasEditPermission ? 'editable' : 'readonly'}">
		<template name="readonly">
				<label value="${person.name}"/>
		</template>
		<template name="editable">
				<textbox value="${person.name}"/>
		</template>
</apply>

动态用法

如果想要在控制器中,使范本重新创建其下的元件时,就要设定 dynamicValue="true",之後在范本内容变更时,可呼叫 Apply.recreate() 重新创建元件来更新浏览器画面。

假如 ${currentUser.hasEditPermission} 有可能会变化,我希望能更新画面,就要这麽写:

<apply id="personBox" 
template="${currentUser.hasEditPermission ? 'editable' : 'readonly'}" 
dynamicValue="true">
		<template name="readonly">
				<label value="${person.name}"/>
		</template>
		<template name="editable">
				<textbox value="${person.name}"/>
		</template>
</apply>
  • 在某个事件倾听器中,当我知道 ${currentUser.hasEditPermission} 已经变了,只要呼叫 recreate() 来重建范本,就能在 <label><textbox> 间切换

<<:  Day 29 - 一秒使用 Tailwind

>>:  追求JS小姊姊系列 Day14 -- 方函式的能力展现:认识生成器,工具人更神气(上)

[Day26] 沟通之术 - 设计师篇

今天是双十连假的最後一天~也是铁人赛接近尾声的倒数第 5 篇~今天就来讲讲跟设计师的沟通之术吧! 前...

Nutanix NCSC-Level-1 Dumps PDF with Actual NCSC-Level-1 Exam Questions

IT business is one of the most famous in the busin...

day 29 - timestamp & 定时执行

我们系统的沟通都是透过timestamp, 包含API参数跟资料库的储存都是以timestamp为主...

Day 1 序言及基本运算元件

我很早就开始接触组合语言,但没有学太久,就没有再碰了,当初学组合语言的原因,是觉得组合语言是人与机器...

[Day12] Key Sequence Detection (KONAMI CODE)

[Day12] Key Sequence Detection (KONAMI CODE) 按键序列检...