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

Vaadin 8:如何实现带折叠/展开表头的简单Grid(兼容IE)

嘿,作为Vaadin 8的新手,你这个需求真的不用大动干戈用TreeGrid,我给你两个简单又兼容IE8+的方案,完全贴合你的需求:

方案一:自定义表头组件+Grid行可见性控制

这个方案的思路是自己做一个带箭头的表头栏,然后控制Grid本身的行显示/隐藏,初始状态下只显示我们自定义的表头,点击箭头后展开所有行。

步骤&代码示例

  1. 首先定义你的数据实体类:
public class MyData {
    private String col1;
    private String col2;

    public MyData(String col1, String col2) {
        this.col1 = col1;
        this.col2 = col2;
    }

    // 必须提供Getter方法,Vaadin Grid需要通过它获取数据
    public String getCol1() { return col1; }
    public String getCol2() { return col2; }
}
  1. 在UI中实现自定义表头和Grid的逻辑:
public class MyUI extends UI {
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        VerticalLayout mainLayout = new VerticalLayout();
        mainLayout.setMargin(true);
        mainLayout.setSpacing(true);
        setContent(mainLayout);

        // 模拟你的数据列表
        List<MyData> dataList = Arrays.asList(
                new MyData("第一行第一列", "第一行第二列"),
                new MyData("第二行第一列", "第二行第二列"),
                new MyData("第三行第一列", "第三行第二列")
        );

        // 创建Grid并配置列
        Grid<MyData> dataGrid = new Grid<>(MyData.class);
        dataGrid.setItems(dataList);
        dataGrid.removeAllColumns(); // 移除自动生成的列,方便对齐自定义表头
        dataGrid.addColumn(MyData::getCol1).setWidth("50%");
        dataGrid.addColumn(MyData::getCol2).setWidth("50%");

        // 自定义表头行:带箭头的点击区域
        HorizontalLayout customHeader = new HorizontalLayout();
        customHeader.setWidth("100%");
        customHeader.setStyleName("grid-custom-header");
        customHeader.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT);
        customHeader.setSpacing(true);

        // 箭头标签,用FontAwesome图标(Vaadin 8内置支持)
        Label toggleArrow = new Label(FontAwesome.CHEVRON_RIGHT.getHtml());
        toggleArrow.setContentMode(ContentMode.HTML);
        toggleArrow.addStyleName("header-toggle-arrow");
        // 给箭头加点击事件,也可以给整个表头加,看你需求
        toggleArrow.addClickListener(e -> toggleGridRows(dataGrid, toggleArrow));

        // 列标题
        Label col1Title = new Label("列1");
        Label col2Title = new Label("列2");
        col2Title.setWidth("50%");
        col2Title.setStyleName("header-column-title");

        customHeader.addComponents(toggleArrow, col1Title, col2Title);
        customHeader.setExpandRatio(col2Title, 1); // 让第二列标题占满剩余宽度

        // 把自定义表头和Grid加入主布局
        mainLayout.addComponents(customHeader, dataGrid);

        // 初始状态隐藏Grid的所有行,只显示自定义表头
        dataGrid.setRowsVisible(false);
        // 隐藏Grid默认的表头,避免重复
        dataGrid.addStyleName("hide-default-header");
    }

    // 封装切换行显示/隐藏的逻辑
    private void toggleGridRows(Grid<?> grid, Label arrowLabel) {
        boolean isRowsVisible = grid.isRowsVisible();
        grid.setRowsVisible(!isRowsVisible);
        // 切换箭头图标
        arrowLabel.setValue(isRowsVisible ? FontAwesome.CHEVRON_RIGHT.getHtml() : FontAwesome.CHEVRON_DOWN.getHtml());
    }

    @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
    @VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
    public static class MyUIServlet extends VaadinServlet {
    }
}
  1. 加一点CSS样式,让表头看起来更协调(可以放在你的theme.scss里):
.grid-custom-header {
    background-color: #f0f0f0;
    border: 1px solid #e0e0e0;
    padding: 8px 12px;
    cursor: pointer; /* 提示用户可以点击 */
}

.header-toggle-arrow {
    font-size: 14px;
    color: #333;
}

.header-column-title {
    font-weight: bold;
}

.hide-default-header .v-grid-header {
    display: none;
}

方案二:复用Grid默认表头实现切换

如果你不想自己做表头,可以直接给Grid默认的表头单元格加箭头和点击事件,控制行的显示,代码更简洁:

代码示例

public class MyUI extends UI {
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        VerticalLayout mainLayout = new VerticalLayout();
        mainLayout.setMargin(true);
        setContent(mainLayout);

        List<MyData> dataList = Arrays.asList(
                new MyData("数据1-1", "数据1-2"),
                new MyData("数据2-1", "数据2-2")
        );

        Grid<MyData> dataGrid = new Grid<>(MyData.class);
        dataGrid.setItems(dataList);
        dataGrid.setColumnOrder("col1", "col2");

        // 获取Grid默认的表头行
        Grid.HeaderRow headerRow = dataGrid.getDefaultHeaderRow();
        Grid.HeaderCell firstColHeader = headerRow.getCell(dataGrid.getColumn("col1"));

        // 给第一列表头设置带箭头的内容
        Label headerContent = new Label(FontAwesome.CHEVRON_RIGHT.getHtml() + " 列1");
        headerContent.setContentMode(ContentMode.HTML);
        headerContent.setStyleName("clickable-header");
        firstColHeader.setComponent(headerContent);

        // 初始隐藏行
        dataGrid.setRowsVisible(false);

        // 表头点击事件
        headerContent.addClickListener(e -> {
            boolean visible = dataGrid.isRowsVisible();
            dataGrid.setRowsVisible(!visible);
            // 更新箭头和标题
            String arrowHtml = visible ? FontAwesome.CHEVRON_RIGHT.getHtml() : FontAwesome.CHEVRON_DOWN.getHtml();
            headerContent.setValue(arrowHtml + " 列1");
        });

        mainLayout.addComponent(dataGrid);
    }

    // 数据类和Servlet部分和方案一一致,这里省略
}

对应的CSS:

.clickable-header {
    cursor: pointer;
    font-weight: bold;
}

兼容性说明

这两个方案都只用了Vaadin 8的核心组件(Grid、HorizontalLayout、Label等),完全兼容IE8及以上版本。如果你的项目还没配置IE8兼容,记得在web.xml里加下面的配置:

<context-param>
    <param-name>vaadin.ie8.compatibility</param-name>
    <param-value>true</param-value>
</context-param>

作为Vaadin新手,这种组合核心组件的方式既轻量又容易维护,完全没必要用TreeGrid这种复杂组件~

内容的提问来源于stack exchange,提问作者T. Phillips

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:09:50