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

如何在Vaadin 23 Grid中实现多层级图书数据展示与编辑

在线图书馆图书列表展示与编辑方案建议

需求说明

  • 需展示最多数千条按年份排序的历史小说数据,由Web服务提供
  • 数据字段繁杂,需采用多行折叠结构实现多层级展示(如主图书信息→详情→读者评论的层级折叠)
  • 支持部分字段编辑:读者可编辑/删除自己的评论
  • 曾考虑TreeGrid(因要求所有项为同一类放弃),现评估Grid+Accordion组合的可行性

Book实体类代码

@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, defaultImpl = Book.class)
@JsonSubTypes(@JsonSubTypes.Type(value = Series.class))
public class Book implements Serializable {

    private static final long serialVersionUID = 1L;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String bookId;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private List<Author> authors;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String title;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String url;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Date publishedOn;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String isbn;
    @JsonIgnore
    private Date addedOn;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String addedBy;
    @JsonIgnore
    private Date updatedOn;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String status;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String annotation;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Integer year;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String country;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private byte[] highlight;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String commentary;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Short rating;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Short seriasVolNum;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private List<String> tags;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private Book seriesId;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private List<ReadersReview> readersReviews;
    // Setters and getters
}

可行技术方案

1. 自定义折叠行的Grid(推荐)

实现思路

基于普通Grid组件,为每行设计主信息+可展开详情区的结构:

  • 主行展示核心信息:书名、作者、年份、评分等
  • 点击主行展开下方多行区域,展示注释、标签、读者评论等详情
  • 评论区再做二级折叠:默认展示评论内容,点击编辑按钮展开评论编辑表单

关键细节

  • 用虚拟滚动优化大数据量渲染:只渲染可视区域内的行,避免DOM节点过多导致卡顿
  • 为每行维护展开/折叠状态,通过前端状态管理控制详情区的显示/隐藏
  • 评论编辑逻辑:点击评论项的编辑按钮,切换到编辑模式,提交后调用后端接口更新数据,同时刷新对应评论项

优势

  • 兼容大数据量场景,性能可控
  • 完全自定义展示结构,适配复杂字段的分层需求
  • 编辑逻辑易实现,无需依赖特殊组件

2. Accordion分组+内嵌Grid/列表

实现思路

结合Accordion的分组折叠能力与Grid的列表展示:

  • 按年份(或其他维度)用Accordion做一级分组,每个面板对应一个年份区间的图书
  • 每个Accordion面板内嵌入Grid展示该年份的图书主信息,图书行同样支持展开详情与评论区

关键细节

  • 前端或后端按年份预分组数据,减少前端渲染压力
  • 内嵌Grid同样启用虚拟滚动,处理单年份下的大量图书
  • 评论编辑逻辑同方案1,在展开的详情区内实现

优势

  • 天然契合“按年份排序”的需求,层级清晰
  • Accordion的折叠/展开能力无需自行开发,降低实现成本

3. 适配TreeGrid的方案

实现思路

虽然TreeGrid要求节点为同一类型,但可通过包装统一节点类绕过限制:

  • 创建通用TreeNode类,包含节点类型(BOOK/REVIEW)、关联数据(Book或ReadersReview)、父节点ID等字段
  • 将Book对象转换为父节点,其下的每个ReadersReview转换为子节点
  • 配置TreeGrid的列渲染规则,根据节点类型展示对应内容(图书信息或评论内容),评论节点添加编辑/删除按钮

关键细节

  • 前端负责数据转换,将Book列表转为TreeGrid可识别的树形结构
  • 配置TreeGrid的展开/折叠逻辑,默认展开图书节点,评论节点可单独折叠
  • 编辑评论时,直接在TreeGrid的评论节点行内渲染编辑表单,提交后更新节点数据

优势

  • TreeGrid自带成熟的折叠/展开、层级管理能力,无需自行实现状态逻辑
  • 适合有明确层级关系的内容展示

通用注意事项

  • 所有方案必须启用虚拟滚动,处理数千条数据的性能问题
  • 编辑操作需做权限校验:仅允许评论作者编辑/删除自己的评论,前端可先做校验,后端再做二次验证
  • 数据更新后采用局部刷新,避免重新渲染整个列表,提升用户体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 19:35:17