跳至主要内容

Rendering

在 ChatGPT 中打开
24.00
Java API

渲染器控制每列中的每个单元格如何显示。它不是显示原始值,而是将每个单元格的数据转换为样式文本、图标、徽章、链接、操作按钮或任何其他使数据更易于阅读和操作的视觉元素。

渲染完全在浏览器中进行。服务器发送原始数据,客户端处理呈现,无论行数多少,“表格”都能快速响应。

使用 setRenderer() 为列分配渲染器。渲染器统一应用于该列的每个单元格:

TextRenderer<MusicRecord> renderer = new TextRenderer<>();
renderer.setTheme(Theme.PRIMARY);

table.addColumn("title", MusicRecord::getTitle).setRenderer(renderer);
渲染器与值提供者

如果您只需要转换或格式化单元格值,而不需要生成任何 DOM 结构,使用值提供者。渲染器为每个渲染的行创建额外的 DOM 元素,这在渲染时会有开销。保留渲染器用于视觉输出,例如图标、徽章、按钮或任何基于 HTML 的呈现。

webforJ随附内置渲染器,适用于最常见的用例。对于您的应用程序特定需求,请扩展 Renderer 并实现 build() 以返回一个在浏览器中运行的 lodash 模板字符串,用于每个单元格。

常见渲染器

以下示例演示四个常用渲染器,并展示了 setRenderer() 模式的实际应用。

TextRenderer

以普通或样式文本的形式显示单元格内容。应用主题颜色或文本修饰,使列在不改变其结构的情况下突出显示,例如将优先级字段高亮为红色或将关键标识符加粗。

TextRenderer<MusicRecord> renderer = new TextRenderer<>();
renderer.setTheme(Theme.PRIMARY);
renderer.setDecorations(EnumSet.of(TextDecoration.BOLD));

table.addColumn("title", MusicRecord::getTitle).setRenderer(renderer);

BadgeRenderer

将单元格值包装在徽章元素中。支持主题、扩展、颜色种子(根据独特值自动分配不同颜色)以及可选的前导图标。用于分类值,如标签、类型或标签,在这些情况下,独特的视觉元素可以帮助用户快速浏览和比较行。

BadgeRenderer<MusicRecord> renderer = new BadgeRenderer<>();
renderer.setTheme(BadgeTheme.PRIMARY);

table.addColumn("musicType", MusicRecord::getMusicType).setRenderer(renderer);

BooleanRenderer

用图标替换 truefalsenull 值。用于任何 true/false 列,其中图标比文本更快速地传达值,例如功能标志、活动/不活动状态或选择字段。

// 默认图标
BooleanRenderer<Task> renderer = new BooleanRenderer<>();
table.addColumn("completed", Task::isCompleted).setRenderer(renderer);

// 自定义图标
BooleanRenderer<Task> custom = new BooleanRenderer<>(
TablerIcon.create("thumb-up").setTheme(Theme.SUCCESS),
TablerIcon.create("thumb-down").setTheme(Theme.DANGER)
);
table.addColumn("completed", Task::isCompleted).setRenderer(custom);

CurrencyRenderer

使用提供的 Locale 规则将数字值格式化为货币金额。用于任何货币列,其中区域设置正确的格式(符号、分隔符、小数位数)很重要。

// 美元
table.addColumn("cost", MusicRecord::getCost)
.setRenderer(new CurrencyRenderer<>(Locale.US));

// 欧元,使用德国区域设置
table.addColumn("retail", MusicRecord::getRetail)
.setRenderer(new CurrencyRenderer<>(Locale.GERMANY));

条件渲染

ConditionalRenderer 根据单元格的值选择不同的渲染器。条件按顺序评估;第一个匹配的条件将生效。可以使用 otherwise() 设置一个备选方案。

以下示例展示了条件渲染应用于发票状态列,根据值在 BadgeRenderer 变体之间切换:

显示代码

它也非常适合数字阈值。此服务器仪表板使用 ConditionalRenderer 根据 CPU 和内存使用水平切换 ProgressBarRenderer 主题:

显示代码

条件 API

条件使用静态工厂方法构建,并可以通过 and()or()negate() 进行组合。

// 值相等
Condition.equalTo("active")
Condition.equalToIgnoreCase("active")
Condition.in("active", "pending", "new")

// 数字比较
Condition.greaterThan(100)
Condition.lessThanOrEqual(0)
Condition.between(10, 50)

// 布尔/空值
Condition.isTrue()
Condition.isFalse()
Condition.isEmpty()

// 字符串匹配
Condition.contains("error")
Condition.containsIgnoreCase("warn")

// 组合
Condition.greaterThan(0).and(Condition.lessThan(100))
Condition.isEmpty().or(Condition.equalTo("N/A"))
Condition.isTrue().negate()

// 跨列检查
Condition.column("status").equalTo("active")

// 原始 JavaScript 表达式
Condition.expression("cell.value % 2 === 0")

复合渲染

CompositeRenderer 在单个单元格中使用灵活布局并排组合多个渲染器。用于将图标与文本配对、显示头像与名称并排,或者在状态指示器旁边堆叠徽章。

下面的员工目录在员工列上使用了 CompositeRenderer,以显示每个员工名称旁边的自动生成头像:

显示代码

自定义渲染器

当没有适合您用例的内置渲染器时,扩展 Renderer 并实现 build()。该方法返回一个在浏览器中运行的 lodash 模板字符串,针对该列的每个单元格表示为 HTML 和 JavaScript 的组合。

创建自定义渲染器

步骤 1: 扩展 Renderer,提供您的行数据类型。

public class RatingRenderer extends Renderer<MusicRecord> {

步骤 2: 重写 build() 并返回一个 lodash 模板字符串。

  @Override
public String build() {
return /* html */"""
<%
const rating = Number(cell.value);
const stars = Math.round(Math.min(Math.max(rating, 0), 5));
const full = '★'.repeat(stars);
const empty = '☆'.repeat(5 - stars);
%>
<span><%= full %><%= empty %></span>
<span style="color: var(--dwc-color-body-text)">(<%= rating.toFixed(1) %>)</span>
""";
}
}

步骤 3: 将渲染器分配给列。

table.addColumn("rating", MusicRecord::getRating)
.setRenderer(new RatingRenderer());
提示

有关如何使用 Lodash 语法访问单元格信息并创建信息丰富的渲染器的更多信息,请参阅此参考部分

访问多个列

使用 cell.row.getValue("columnId") 在模板内读取兄弟列。这对于组合字段、计算差异或交叉引用相关数据很有用。

public class ArtistAvatarRenderer extends Renderer<MusicRecord> {
@Override
public String build() {
return /* html */"""
<%
const name = cell.row.getValue("artist");
const initials = name
? name.split(' ').map(w => w.charAt(0)).join('').substring(0, 2).toUpperCase()
: '?';
%>
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 28px; height: 28px; border-radius: 50%;
background: var(--dwc-color-primary); color: white;
display: flex; align-items: center; justify-content: center;
font-size: 11px; font-weight: 600;">
<%= initials %>
</div>
<span><%= name %></span>
</div>
""";
}
}

点击事件

IconButtonRendererButtonRenderer 提供 addClickListener()。点击事件通过 e.getItem() 提供对行数据对象的访问。

IconButtonRenderer<MusicRecord> deleteBtn = new IconButtonRenderer<>(
TablerIcon.create("trash").setTheme(Theme.DANGER)
);
deleteBtn.addClickListener(e -> {
MusicRecord record = e.getItem();
repository.delete(record);
table.refresh();
});

table.addColumn("delete", r -> "").setRenderer(deleteBtn);

性能:懒渲染 25.12

对于使用视觉上昂贵的渲染器的列,如徽章、进度条、头像或 Web 组件,启用懒渲染以提高滚动性能。

table.addColumn("status", Order::getStatus)
.setRenderer(new BadgeRenderer<>())
.setLazyRender(true);

当在列上设置 setLazyRender(true) 时,单元格在用户滚动时显示轻量级动画占位符。实际单元格内容在滚动停止后呈现。此设置为列级,因此您可以根据需要仅对受益的列进行选择性启用。

显示代码

何时启用懒渲染

单元格渲染器在 DOM 中创建更多实体,这意味着在渲染过程中需要更多 CPU 工作,无论是哪个渲染器生成它。

如果确实需要使用渲染器,则懒渲染可以帮助降低性能影响。如果您只需要更改或格式化值,且不需要创建复杂的 DOM,请改为使用值提供者来转换值。

内置渲染器参考

webforJ 配备了全面的渲染器集合,以满足最常见的用例。使用 column.setRenderer(renderer) 将其分配给列。

显示代码

文本和标签

25.12

以普通或样式文本的形式显示单元格内容。支持主题颜色和文本修饰,如粗体、斜体和下划线。

TextRenderer renderer = new TextRenderer<>();
renderer.setTheme(Theme.PRIMARY);
renderer.setDecorations(EnumSet.of(TextDecoration.BOLD));

table.addColumn("title", MusicRecord::getTitle).setRenderer(renderer);
25.12

将单元格值包装在徽章元素中。支持主题、扩展、颜色种子(根据独特值自动分配不同颜色)以及可选的前导图标。

BadgeRenderer renderer = new BadgeRenderer<>();
renderer.setTheme(BadgeTheme.PRIMARY);

table.addColumn("musicType", MusicRecord::getMusicType).setRenderer(renderer);
25.12

当单元格值为 null 或空时,呈现可配置的回退字符串;否则按原样呈现值。

table.addColumn("notes", MusicRecord::getNotes)
.setRenderer(new NullRenderer<>("N/A"));

状态和指示器

25.12

用图标替换 truefalsenull 值。默认为对勾、叉和破折号。

// 默认图标
BooleanRenderer renderer = new BooleanRenderer<>();
table.addColumn("completed", Task::isCompleted).setRenderer(renderer);

// 自定义图标
BooleanRenderer custom = new BooleanRenderer<>(
TablerIcon.create("thumb-up").setTheme(Theme.SUCCESS),
TablerIcon.create("thumb-down").setTheme(Theme.DANGER)
);
25.12

在单元格值的左侧呈现一个小彩色点。将各个值映射到主题、CSS 颜色字符串或 java.awt.Color 实例。

StatusDotRenderer renderer = new StatusDotRenderer<>();
renderer.addMapping("Active", Theme.SUCCESS);
renderer.addMapping("Pending", Theme.WARNING);
renderer.addMapping("Cancelled", Theme.DANGER);

table.addColumn("status", Order::getStatus).setRenderer(renderer);

数字、货币和日期

25.12

使用提供的 Locale 规则将数字值格式化为货币金额。

// 美元
table.addColumn("cost", MusicRecord::getCost)
.setRenderer(new CurrencyRenderer<>(Locale.US));

// 欧元,使用德国区域设置
table.addColumn("retail", MusicRecord::getRetail)
.setRenderer(new CurrencyRenderer<>(Locale.GERMANY));
25.12

将数值显示为百分比。将第二个构造函数参数设置为 false,以防止在文本下方呈现细进度条。

PercentageRenderer renderer = new PercentageRenderer<>(Theme.PRIMARY, true);
table.addColumn("completion", Task::getCompletion).setRenderer(renderer);
25.12

呈现具有可配置最小值和最大值、无确定模式,以及条纹或动画显示的全宽进度条。使用 setText() 与 lodash 表达式在条上覆盖自定义文本。

ProgressBarRenderer renderer = new ProgressBarRenderer<>();
renderer.setMax(100);
renderer.setTheme(Theme.SUCCESS);
renderer.setTextVisible(true);
renderer.setText("<%= cell.value %>/100");

table.addColumn("progress", Task::getProgress).setRenderer(renderer);
25.12

对字符串值应用字符掩码。# 匹配任何数字; 字面字符被保留。有关所有支持的掩码字符,请参阅文本掩码规则

table.addColumn("ssn", Employee::getSsn)
.setRenderer(new MaskedTextRenderer<>("###-##-####"));
25.12

使用带有区域设置感知分隔符的模式字符串对数值进行格式化。0 强制一个数字; # 是可选的。有关所有支持的掩码字符,请参阅数字掩码规则

table.addColumn("price", Product::getPrice)
.setRenderer(new MaskedNumberRenderer<>("###,##0.00", Locale.US));
25.12

使用模式令牌对日期或时间值进行格式化:%Mz(月份)、%Dz(日期)、%Yz(年份)等。有关所有可用令牌,请参阅日期掩码规则

table.addColumn("released", MusicRecord::getReleaseDate)
.setRenderer(new MaskedDateTimeRenderer<>("%Mz/%Dz/%Yz"));
25.12

将单元格值包装在 mailto: 锚中。默认情况下,主要主题的邮件图标作为视觉提示。

// 默认邮件图标
table.addColumn("email", Contact::getEmail)
.setRenderer(new EmailRenderer<>());

// 自定义图标
table.addColumn("email", Contact::getEmail)
.setRenderer(new EmailRenderer<>(TablerIcon.create("at")));
25.12

将单元格值包装在 tel: 锚中。在移动设备上,点击时打开拨号器。默认情况下显示主要主题的电话图标。

// 默认电话图标
table.addColumn("phone", Contact::getPhone)
.setRenderer(new PhoneRenderer<>());

// 自定义图标
table.addColumn("phone", Contact::getPhone)
.setRenderer(new PhoneRenderer<>(TablerIcon.create("device-mobile")));
25.12

呈现可点击的锚元素。href 支持 lodash 模板表达式,因此您可以根据单元格值动态构建 URL。

AnchorRenderer renderer = new AnchorRenderer<>();
renderer.setHref("https://www.google.com/search?q=<%= cell.value %>");
renderer.setTarget("_blank");

table.addColumn("title", MusicRecord::getTitle).setRenderer(renderer);
25.12

显示一张图像。src 属性支持 lodash 模板表达式,因此每行可以显示不同的图像。

ImageRenderer renderer = new ImageRenderer<>();
renderer.setSrc("https://placehold.co/40x40?text=<%= cell.value %>");
renderer.setAlt("封面");

table.addColumn("cover", MusicRecord::getArtist).setRenderer(renderer);

人物和头像

25.12

呈现头像组件。首字母自动从单元格值中派生。支持主题和回退图标。

AvatarRenderer renderer = new AvatarRenderer<>();
renderer.setTheme(AvatarTheme.PRIMARY);
renderer.setIcon(TablerIcon.create("user"));

table.addColumn("artist", MusicRecord::getArtist).setRenderer(renderer);

图标和操作

24.00

呈现一个独立的图标。附加点击监听器以实现交互行为。

IconRenderer renderer = new IconRenderer<>(TablerIcon.create("music"));
table.addColumn("type", MusicRecord::getMusicType).setRenderer(renderer);
25.12

呈现一个可点击的图标按钮。点击事件通过 e.getItem() 揭示行项,非常适合行级操作。

IconButtonRenderer renderer = new IconButtonRenderer<>(TablerIcon.create("edit"));
renderer.addClickListener(e -> openEditor(e.getItem()));

table.addColumn("actions", r -> "").setRenderer(renderer);
24.00

在单元格内部渲染完整的 Button 组件。

ButtonRenderer renderer = new ButtonRenderer<>("编辑");
renderer.setTheme(ButtonTheme.PRIMARY);
renderer.addClickListener(e -> openEditor(e.getItem()));

table.addColumn("edit", r -> "编辑").setRenderer(renderer);
24.00

使用 lodash 模板内容字符串呈现任何 HTML 元素。这是没有适合的内置渲染器的情况下的逃生通道。

ElementRenderer renderer = new ElementRenderer<>("span", "<%= cell.value %>");
table.addColumn("custom", MusicRecord::getTitle).setRenderer(renderer);

模板参考

渲染器提供了一种强大的机制,用于自定义数据在 Table 中的显示方式。主类 Renderer 旨在扩展以创建基于 lodash 模板的自定义渲染器,使动态和交互式内容渲染成为可能。

Lodash 模板使得直接将 HTML 插入表格单元格成为可能,使其在表格中渲染复杂单元格数据方面极为有效。此方法允许根据单元格数据动态生成 HTML,促进丰富和交互式表格单元格内容的制作。

Lodash 语法

以下部分概述了 Lodash 语法的基础知识。虽然这不是一个详尽的或全面的概述,但可以帮助您开始在 Table 组件中使用 Lodash。

Lodash 模板语法概述:

  • <%= ... %> - 插值值,将 JavaScript 代码的结果插入模板中。
  • <% ... %> - 执行 JavaScript 代码,允许循环、条件等。
  • <%- ... %> - 转义 HTML 内容,以确保插值数据免受 HTML 注入攻击。

使用单元格数据的示例:

1. 简单值插值:直接显示单元格的值。

<%= cell.value %>

2. 条件渲染:使用 JavaScript 逻辑有条件地渲染内容。

<% if (cell.value > 100) { %> '高' <% } else { %> '正常' <% } %>

3. 结合数据字段:使用单元格的多个数据字段渲染内容。

<%= cell.row.getValue('firstName') + ' ' + cell.row.getValue('lastName') %>

4. 转义 HTML 内容:安全地渲染用户生成的内容。

渲染器在客户端可以访问详细的单元格、行和列属性:

TableCell 属性:

属性类型描述
columnTableColumn关联的列对象。
firstboolean指示该单元格是否为行中的第一个。
idString单元格 ID。
indexint单元格在其行中的索引。
lastboolean指示该单元格是否为行中的最后一个。
rowTableRow与单元格关联的行对象。
valueObject单元格的原始值,直接来自数据源。

TableRow 属性:

属性类型描述
cellsTableCell[]行中的单元格。
dataObject由应用程序提供的行数据。
evenboolean指示行是否为偶数(用于样式目的)。
firstboolean指示行是否为表格中的第一个。
idString行的唯一 ID。
indexint行索引。
lastboolean指示行是否为表格中的最后一个。
oddboolean指示行是否为奇数(用于样式目的)。

TableColumn 属性:

属性类型描述
alignColumnAlignment列的对齐方式(左、中、右)。
idString从行对象获取单元格数据的字段。
labelString在列标题中渲染的名称。
pinnedColumnPinDirection列的固定方向(左、右、自动)。
sortableboolean如果为 true,则可以对该列进行排序。
sortSortDirection列的排序顺序。
typeColumnType列的类型(文本、数字、布尔值等)。
minWidthnumber列的最小宽度(以像素为单位)。