iT邦幫忙

2021 iThome 鐵人賽

DAY 14
1
Modern Web

ZK 30天速成系列 第 14

Shadow Element:控制 UI 元件的元件

  • 分享至 

  • xImage
  •  

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> 間切換

上一篇
資料驅動的元件
下一篇
模組化、重用使用者介面
系列文
ZK 30天速成30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言