Shadow Element:建构新增、删除、排序集合物件的介面与功能

走访集合物件

<forEach> 跟 Listbox, Grid 同样支援 model-driven rendering,也就是基於 ListModel 来绘制画面,你只要变更 ListModel 物件内容,ZK 会自动帮你更新到浏览器页面。例如下面是一个新增、删除、排序名字列表的应用:

显示名字列表

https://ithelp.ithome.com.tw/upload/images/20211002/200506216JlBT9Fp2h.jpg

<groupbox width="450px" apply="quickstart.shadow.ForEachComposer" mold="3d">
    <div>
        <forEach id="namesList" var="name">
            <span  sclass="nameTag">
                <label value="${name}"/>
            </span>
        </forEach>
    </div>
</groupbox>
  • 指定 <forEach> id 好让我可以在控制器中取得参照。var 属性是把预设的隐含变数名称 each 改名为 name,这样在 <forEach> 内部就必须要用 ${name} 来存取集合物件内每个物件,这是一个增加可读性的功能,不改也不影响功能。
public class ForEachComposer extends SelectorComposer<Component> {
    
    @Wire("::shadow#namesList")
    private ForEach namesList;
    private ListModelList<String> namesModel;

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        namesModel = new ListModelList<String>(new String[] {"Chris", "Elisabeth", "Aaron", "Berta", "Daniel"});
        namesList.setItems(namesModel);
        namesList.recreate();
  • setItems() 把初始化好的资料模型 ListModelList 赋予给 nameList,再呼叫 recreate() 重建 <forEach> 的元件

新增名字到列表中

https://ithelp.ithome.com.tw/upload/images/20211002/20050621LZvgMCB9co.jpg
增加一个 <textbox> 并把事件转发到根元件上。

<groupbox width="450px" apply="quickstart.shadow.ForEachComposer" mold="3d">
    <div>
        <forEach id="namesList" var="name">
            <span  sclass="nameTag">
                <label value="${name}"/>
            </span>
        </forEach>
    </div>
		<textbox forward="onOK=onAddName" placeholder="New Name + ENTER"/>
</groupbox>
  • onOK 事件发生在使用者在 <textbox> 内按下 Enter 键,这样好处是可以免去点击「增加」按钮的操作
  • 转发事件若不指定目标元件,预设是 ID space owner,但因为画面上没有实作 IdSpace的元件,就会转发到「根元件」,也就是 <groupbox>
@Override
public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp);
    ...

    comp.addEventListener("onAddName", (EventListener<ForwardEvent>)this::addName);
}

private void addName(ForwardEvent event) {
    Textbox nameInput = (Textbox) event.getOrigin().getTarget();
    Optional.ofNullable(nameInput.getValue())
            .filter(v -> !namesModel.contains(v)) //ignore duplicates
            .ifPresent(namesModel::add);
    nameInput.setValue("");
}
  • 另一种注册事件倾听器的方法 addEventListener()
  • 呼叫 namesModel::add,zk 就会帮你通知 <forEach> 并更新页面

移除名字

https://ithelp.ithome.com.tw/upload/images/20211002/20050621wnOvonReXv.jpg
在名字後面增加一个 X 图示来作为「移除」按钮

<forEach id="namesList" var="name">
    <span sclass="nameTag" >
        <label value="${name}"/>
        <a forward="onClick=onRemoveName(${name})" iconSclass="z-icon-times"/>
    </span>
</forEach>
  • 将「移除」按钮的 onClick 事件转发到 <groupbox>,这样的好处是,我可以统一把倾听器都注册在 <groupbox>,比较好维护。如果注册在内部子元件 <a>上,如果未来要换成别的元件,就要修改程序
  • 转发的时候可以带参数 onRemoveName(${name}):这写法就能把名字当作参数传进倾听器中
public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp);
    ...
    comp.addEventListener("onRemoveName", event -> namesModel.remove((String) event.getData()));
}
  • event.getData() 取得先前传入的参数(名字)

排序

https://ithelp.ithome.com.tw/upload/images/20211002/20050621oyyahsXG8Q.jpg
加2个排序按钮,分别是升序与降序排序:

<button forward="onSortAsc" iconSclass="z-icon-sort-alpha-asc"/>
<button forward="onSortDesc" iconSclass="z-icon-sort-alpha-desc"/>

呼叫 ListModelList.sort() 来排序即可

@Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        ...
        comp.addEventListener("onSortAsc", event -> namesModel.sort(String.CASE_INSENSITIVE_ORDER));
        comp.addEventListener("onSortDesc", event -> namesModel.sort(String.CASE_INSENSITIVE_ORDER.reversed()));
        ...
    }

清除全部

增加一个清除全部按钮
https://ithelp.ithome.com.tw/upload/images/20211002/20050621lInsy44XOp.jpg

<button forward="onClearAll" iconSclass="z-icon-user-times" tooltiptext="clear all"/>

呼叫 ListModelList.clear()

@Override
public void doAfterCompose(Component comp) throws Exception {
    super.doAfterCompose(comp);
    ...

    comp.addEventListener("onClearAll", event -> namesModel.clear());
    ...
}

透过以上例子应该可以看出,用 <forEach> 再搭配 ListModelList 即可以快速做出新增、删除等各种操作集合物件的功能。


<<:  Dungeon Mizarka 020

>>:  IOS、Python自学心得30天 Day-29 连接Firebase辨识

DAY5 绘制介面

上一篇我们完成了wireframe的绘制,这次我们要将草稿跟库拉皮卡一样,没有办法下船更具现化一点,...

自组NAS:针对unRaid

前面讲了那麽多,当然在部属unRaid还是要优先考虑设备的选择 当然用淘汰的旧电脑也是可以(小雨这次...

Android 不负责任系列 - emcthye FxRate(汇率)

来源 : emcthye - FxRate 架构图 MVP Base CurrencyListAct...

Day28 资安小结 - 红队与蓝队 ( 内附名字由来 )

打了这麽多的技术文,突然发现我好像都没有介绍到资安的基础,所以最後的这 3 篇文章可能就是做个资安的...

Day 0x9 UVa272 TEX Quotes

Virtual Judge ZeroJudge 题意 \TeX/ \LaTeX/ 输入一字串,重新...