You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ZK 7.0.3 ListBox多列排序及排序图标保持方法问询

嘿,我刚好在ZK 7.0.3里处理过类似的多列排序需求,结合表头图标持久显示的问题,给你一步步拆解怎么实现:

一、实现按第一列、第二列依次的多列排序

ZK的ListBox默认只支持单列排序,多列排序需要我们自己维护排序规则和逻辑,核心思路是监听表头点击事件,记录排序列的顺序和升降序状态,然后手动对列表数据进行排序。

1. 先写ZUL页面的ListBox结构

给每个表头绑定点击事件,传递对应的列名,同时开启sort="auto"来让表头默认有排序图标(后续我们会手动控制图标状态):

<listbox id="myListbox" model="@load(vm.itemList)">
    <listhead>
        <!-- 给表头加id方便后续获取,传递列名col1 -->
        <listheader id="col1Header" label="第一列" sort="auto" onClick="@command('sortColumn', col='col1')" />
        <listheader id="col2Header" label="第二列" sort="auto" onClick="@command('sortColumn', col='col2')" />
        <!-- 其他列按需添加 -->
    </listhead>
    <listitem self="@{each=item}">
        <listcell label="@load(item.col1)" />
        <listcell label="@load(item.col2)" />
    </listitem>
</listbox>

2. 在ViewModel里维护排序状态

定义两个变量来记录排序的列顺序和每列的升降序:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zul.Listbox;
import org.zkoss.zul.Listheader;
import org.zkoss.zul.Listhead;
import org.zkoss.zul.SortDirection;

// 假设你的ViewModel类是这样的
public class MyViewModel {
    // 存储排序列的顺序,第一个是主排序列,第二个是次排序列
    private List<String> sortColumns = new ArrayList<>();
    // 存储每列的升降序状态,key是列名,value是"asc"或"desc"
    private Map<String, String> sortOrders = new HashMap<>();
    // 你的列表数据,假设Item是你的数据实体类
    private List<Item> itemList;

    // 初始化数据的方法,这里省略...

3. 处理表头点击事件,执行排序

写一个sortColumn命令来处理点击逻辑,维护排序状态并触发排序:

@Command
public void sortColumn(@BindingParam("col") String col) {
    // 如果点击的列已经在排序列表里,切换它的升降序
    if (sortColumns.contains(col)) {
        String currentOrder = sortOrders.get(col);
        sortOrders.put(col, "asc".equals(currentOrder) ? "desc" : "asc");
    } else {
        // 如果是新列,添加到排序列表,默认升序
        sortColumns.add(col);
        sortOrders.put(col, "asc");
        // 只保留最多两列排序(符合需求:按第一、第二列依次排)
        if (sortColumns.size() > 2) {
            sortColumns.remove(0);
        }
    }
    // 执行列表排序
    sortItemList();
    // 更新表头的排序图标
    updateHeaderSortIcons();
}

4. 实现多列排序的核心逻辑

编写sortItemList方法,根据我们维护的排序规则对列表进行排序:

private void sortItemList() {
    Collections.sort(itemList, new Comparator<Item>() {
        @Override
        public int compare(Item o1, Item o2) {
            // 先按第一排序列比较
            String firstCol = sortColumns.get(0);
            int firstCompare = compareByColumn(o1, o2, firstCol);
            // 如果第一列有差异,直接返回结果,注意升降序
            if (firstCompare != 0) {
                return "asc".equals(sortOrders.get(firstCol)) ? firstCompare : -firstCompare;
            }
            // 如果第一列相同,再按第二列比较(如果存在第二排序列)
            if (sortColumns.size() >= 2) {
                String secondCol = sortColumns.get(1);
                int secondCompare = compareByColumn(o1, o2, secondCol);
                return "asc".equals(sortOrders.get(secondCol)) ? secondCompare : -secondCompare;
            }
            return 0;
        }

        // 根据列名获取属性值并比较,这里假设是字符串类型,你可以根据实际类型调整
        private int compareByColumn(Item o1, Item o2, String col) {
            String val1 = getPropertyValue(o1, col);
            String val2 = getPropertyValue(o2, col);
            return val1.compareTo(val2);
        }

        // 映射列名到实体类的属性
        private String getPropertyValue(Item item, String col) {
            if ("col1".equals(col)) {
                return item.getCol1();
            } else if ("col2".equals(col)) {
                return item.getCol2();
            }
            return "";
        }
    });
    // 通知ZK更新视图
    org.zkoss.bind.BindUtils.postNotifyChange(null, null, this, "itemList");
}

注意:如果你的数据是数字、日期类型,要把compareByColumn里的比较逻辑改成对应类型的比较,比如转成Integer或者LocalDate来比较。

二、让表头排序图标保持显示

ZK默认只会给当前“活跃”的排序列显示图标,其他列会清空图标。我们需要手动控制每个表头的sortDirection属性,让参与排序的列一直显示对应的图标。

实现updateHeaderSortIcons方法:

private void updateHeaderSortIcons() {
    // 获取页面上的ListBox组件
    Listbox listbox = (Listbox) Executions.getCurrent().getDesktop().getComponentById("myListbox");
    Listhead listhead = listbox.getListhead();
    
    // 遍历所有表头,设置对应的排序图标
    for (Listheader header : listhead.getListheaders()) {
        String colName = getColNameFromHeader(header);
        if (sortColumns.contains(colName)) {
            // 如果是排序列,设置对应的升降序图标
            String order = sortOrders.get(colName);
            header.setSortDirection("asc".equals(order) ? SortDirection.ASCENDING : SortDirection.DESCENDING);
        } else {
            // 非排序列,清空图标
            header.setSortDirection(SortDirection.NONE);
        }
    }
}

// 根据表头id映射到列名
private String getColNameFromHeader(Listheader header) {
    if ("col1Header".equals(header.getId())) {
        return "col1";
    } else if ("col2Header".equals(header.getId())) {
        return "col2";
    }
    return "";
}

这样每次排序后,所有参与排序的表头都会保留对应的升序/降序图标,直到你再次点击切换状态或者该列被移出排序列表。

额外小提示
  • 如果你的列表用的是ListModelList,可以直接调用listModelList.sort(comparator),这样不需要手动调用postNotifyChange,ZK会自动更新视图。
  • 对于复杂的实体类属性,建议用反射或者Apache BeanUtils来获取属性值,减少硬编码的工作量。

内容的提问来源于stack exchange,提问作者hephestos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:02:49