在表格中显示记录数据 — LWC Datatable 完全指南

全面掌握 lightning-datatable 和 lightning-tree-grid。涵盖组件对比、层次表、内联编辑(updateRecord vs Apex DML)、自定义数据类型(扩展 vs Slot)、布局样式、编辑模板、无障碍双模式、性能与限制。...

📅 2026/7/19 ✍️ ponybai 🏷️ lwc, salesforce

在表格中显示记录数据

在表格中显示记录数据

使用 lightning-datatable 显示行列记录数据,lightning-tree-grid 显示层次结构数据(如 Account 及其关联的 Contacts——子记录通过切换按钮展开/折叠)。两者均不支持移动设备。本章涵盖内联编辑、自定义数据类型(扩展类 vs 插槽两种方式)、布局样式、编辑模板、无障碍和性能。

比较 Datatable 与 Tree-Grid + 层次表

比较与层次表
功能datatabletree-grid
格式化列/自定义类型/行操作/调整列宽/行选择/换行裁剪/行号
列排序/内联编辑/无限滚动
可展开行(层次数据)

Tree-Grid 层次表示例:Apex 返回 Account + 嵌套子查询 Cases → JS 中将 _children 键映射到子记录 → lightning-tree-grid 绑定 key-field="Id" + data={myData} + columns={columns}。每行级操作通过 onrowaction 处理——如用 NavigationMixin.Navigate 导航到编辑页面。支持 expandAll()/collapseAll() 公共方法。

内联编辑 —— 使用 updateRecord 基础实现

内联编辑基础

启用内联编辑需配置:key-field="Id" 关联行与记录、data 绑定数据、columns 定义列(含 editable: true)、onsave 处理器、draft-values 存储编辑值。Apex 方法用 @AuraEnabled(cacheable=true) + WITH USER_MODE

// 列定义——editable:true 启用编辑
const COLS = [
  { label: "First Name", fieldName: FIRSTNAME_FIELD.fieldApiName, editable: true },
  { label: "Last Name", fieldName: LASTNAME_FIELD.fieldApiName, editable: true }, ...
];

async handleSave(event) {
  const records = event.detail.draftValues.slice().map(draft => {
    const fields = Object.assign({}, draft);
    return { fields };
  });
  this.draftValues = [];  // 清除草稿→隐藏 footer
  const promises = records.map(record => updateRecord(record));
  await Promise.all(promises);  // 并行保存所有记录
  await refreshApex(this.contacts);  // 刷新数据
}

编辑后 Tab/点击外部 = footer 出现 Cancel+Save。草稿值格式:[{FirstName:"Sean", Id:"003..."}, ...]——包含编辑字段值和记录 ID。

内联编辑 —— 使用 Apex 批量更新

Apex 批量更新

批量更新推荐单个事务用 Apex:编辑值传给 Apex controller → update DML。由于 Apex 更新不经过 LDS,必须调用 notifyRecordUpdateAvailable(recordIds) 刷新 LDS 缓存。

import updateContacts from "@salesforce/apex/ContactController.updateContacts";
import { notifyRecordUpdateAvailable } from "lightning/uiRecordApi";

async handleSave(event) {
  const updatedFields = event.detail.draftValues;
  const notifyChangeIds = updatedFields.map(row => ({ recordId: row.Id }));
  await updateContacts({ data: updatedFields });           // Apex DML
  notifyRecordUpdateAvailable(notifyChangeIds);             // 通知 LDS 缓存失效
  await refreshApex(this.contacts);                         // 刷新 wire
  this.draftValues = [];
}

// Apex 控制器:JSON.deserialize → update DML

自定义数据类型 —— 扩展 LightningDatatable

扩展自定义类型

标准类型不满足需求时可创建自定义数据类型。标准类型:action/boolean/button/button-icon/currency/date/email/location/number/percent/phone/text/url。

方式一——扩展类:创建新组件继承 LightningDatatable,在 static customTypes 中定义:template(HTML 模板引用)、typeAttributes(传给模板的属性数组)、standardCellLayout(true=标准布局/支持无障碍和键盘导航)。

import LightningDatatable from "lightning/datatable";
export default class MyTable extends LightningDatatable {
  static customTypes = {
    customName: { template: customNameTemplate, standardCellLayout: true, typeAttributes: ["accountName"] },
    customNumber: { template: customNumberTemplate, standardCellLayout: false, typeAttributes: ["status"] },
  };
}
// 模板中用 {typeAttributes.accountName} 访问属性
// 用 {value} 访问当前单元格值

实现时创建包装组件包含扩展的 datatable,定义列(type: "customName"),获取数据并传给 data 属性。

自定义数据类型 —— Slot 动态加载

Slot 动态加载

方式二——Slot:运行时根据上下文动态决定加载哪些自定义类型。创建数据提供器组件——不继承 LightningDatatable,用 @api getDataTypes() 返回类型定义:

// customProvider.js——不继承 LightningDatatable
export default class CustomProvider extends LightningElement {
  @api getDataTypes() {
    return { customPictureType: { template: ..., standardCellLayout: true, typeAttributes: ["pictureUrl"] } };
  }
}

// 在 datatable 中通过 slot 传递
<lightning-datatable key-field="Id" data={contacts.data} columns={columns}>
  <c-custom-provider slot="customdatatypes"></c-custom-provider>
</lightning-datatable>

初始化时可过滤列(去除动态类型),点击按钮→设置完整列数组→自定义类型列出现。使用 connectedCallback 时注意调用 super.connectedCallback()。自定义类型单元格内不能嵌套另一个 lightning-datatable

自定义数据类型 —— 布局、样式与事件

布局样式事件

标准 vs 空白布局:标准布局(standardCellLayout: true)分散内容、左对齐垂直居中、左右小间距、支持无障碍。空白布局(默认)无间距、不支持无障碍。

应用样式:所有行 → cellAttributes: { class: "slds-theme_shade" }。特定行 → class: { fieldName: 'industryClass' }(数据中动态赋值)。仅支持 SLDS 工具类,不支持自定义类。对齐:cellAttributes: { alignment: "right" }。文本换行/裁剪:slds-hyphenate/slds-truncate + wrapText/wrap-text-max-lines

自定义事件:自定义类型中派发 new CustomEvent("photoclick", { bubbles:true, composed:true, detail:{...} }) → 父组件通过 onphotoclick 处理。自定义类型排序时 event.detail.fieldName 返回 undefined——需传入实际字段名。

使自定义数据类型可编辑

可编辑自定义类型

三步启用内联编辑:① 创建编辑模板(*Edit.html)——使用 lightning-input 组件;② 在类型定义中添加 editTemplate;③ 列定义设 editable: true

// customNumberEdit.html——编辑模板
<lightning-input type="number" value={editedValue} label={columnLabel}
    required={required} min={typeAttributes.min} data-inputable="true"></>

// 类型定义中加入 editTemplate
customNumber: { template: ..., editTemplate: customNumberEditTemplate,
    standardCellLayout: true, typeAttributes: ["status", "min"] }

编辑模板支持属性:editedValue(当前值)、columnLabelrequiredtypeAttributes无障碍:data-inputable="true" + standardCellLayout: true 启用操作/导航模式。验证:在子组件中暴露 validity() getter 和 showHelpMessageIfInvalid()限制:仅支持单输入基础组件;不支持 lightning-input-field;服务器端验证规则暂不支持。

Datatable 无障碍 —— 导航与操作模式

无障碍模式

Datatable 提供两种交互模式:导航模式(Tab 在单元格间移动)和操作模式(Enter/Space 进入——聚焦单元格内可操作元素)。自定义类型可编辑时需 data-inputable="true" + standardCellLayout: true 以支持这两种模式。Enter/Space → 进入操作模式 → 可编辑单元格被激活 → Tab 在可操作元素间移动。

性能、显示密度与注意事项

性能与注意事项

性能:大量数据时用无限滚动enable-infinite-loading + loadmore 事件)而非一次性加载。指定字段而非布局以获得更好性能。避免在自定义类型中进行昂贵操作——计算逻辑尽量放在 getter 中利用缓存。

显示密度:支持 Comfy/Compact 两种密度——通过 default-compact 或父组件的 density setting 控制。

关键注意事项:① 仅桌面端(不支持移动设备);② 自定义类型列排序需手动传 fieldName;③ connectedCallback 中必须 super.connectedCallback();④ 不能嵌套 datatable;⑤ 仅支持 SLDS 工具类样式,不支持自定义 CSS 类;⑥ lightning-input-field 不能在 datatable 中使用。

感谢阅读本指南。如需继续学习,请参阅下一章:使用 Wire Service 获取数据。