Vaadin 23中Details组件能否实现懒加载?替代方案咨询
Vaadin Details组件懒加载实现方案
原生Details组件实现懒加载
Vaadin Details默认会预渲染内容,但可以通过监听展开状态变化事件实现懒加载逻辑,不需要替换组件。核心思路是:初始时只渲染标题和占位内容,当用户第一次展开面板时,再异步加载并渲染实际内容。
实现步骤
- 初始化Details时,设置一个占位内容(比如“加载中...”),或者暂时不设置内容
- 给Details添加
opened-changed事件监听器 - 在监听器中判断:如果面板处于展开状态,且内容未加载过,则异步获取数据并替换占位内容
Java代码示例
Details details = new Details("用户详情"); // 初始设置占位内容 details.setContent(new Span("加载中...")); // 监听展开状态变化 details.addOpenedChangeListener(event -> { if (event.isOpened()) { // 检查内容是否已加载,避免重复请求 if (!(details.getContent() instanceof UserInfoComponent)) { // 异步从后端获取数据 CompletableFuture.supplyAsync(() -> userService.getUserDetails(123)) .thenAccept(user -> { // 在UI线程中更新内容 UI.getCurrent().access(() -> { UserInfoComponent content = new UserInfoComponent(user); details.setContent(content); }); }); } } });
TypeScript代码示例
import { Details, Span } from '@vaadin/details'; import { UserInfo } from './models'; const details = new Details('用户详情'); details.content = new Span('加载中...'); details.addEventListener('opened-changed', (event: CustomEvent) => { if (event.detail.value) { // 避免重复加载 if (!(details.content instanceof UserInfoComponent)) { fetch('/api/users/123') .then(res => res.json()) .then((user: UserInfo) => { const content = new UserInfoComponent(user); details.content = content; }); } } });
替代方案
如果原生Details的懒加载逻辑无法满足需求,比如需要更灵活的样式控制或复杂的加载状态管理,可以考虑以下替代方案:
1. 使用Accordion组件
Accordion的面板同样支持opened-changed事件监听,逻辑和Details完全一致,适合需要多个折叠面板的场景:
Accordion accordion = new Accordion(); AccordionPanel panel = accordion.add("订单详情", new Span("加载中...")); panel.addOpenedChangeListener(event -> { if (event.isOpened() && !(panel.getContent() instanceof OrderInfoComponent)) { // 异步加载订单数据并更新内容 } });
2. 自定义折叠面板
用Button配合容器组件(如Div)手动实现折叠逻辑,完全自定义样式和加载流程:
Button toggleBtn = new Button("展开订单详情", new ArrowRightIcon()); Div contentDiv = new Div(); contentDiv.setVisible(false); toggleBtn.addClickListener(e -> { boolean isOpened = contentDiv.isVisible(); if (isOpened) { toggleBtn.setIcon(new ArrowRightIcon()); contentDiv.setVisible(false); } else { toggleBtn.setIcon(new ArrowDownIcon()); // 首次展开时加载内容 if (contentDiv.getChildren().count() == 0) { CompletableFuture.supplyAsync(() -> orderService.getOrderDetails(456)) .thenAccept(order -> UI.getCurrent().access(() -> { contentDiv.add(new OrderInfoComponent(order)); })); } contentDiv.setVisible(true); } }); add(toggleBtn, contentDiv);
内容的提问来源于stack exchange,提问作者alexanoid
相关产品推荐
相关产品推荐

