news 2026/9/12 21:10:51

ToolJet List View 组件完全指南:数据列表、分页与子组件控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ToolJet List View 组件完全指南:数据列表、分页与子组件控制

ToolJet List View 组件完全指南:数据列表、分页与子组件控制

【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet

List View 是 ToolJet 应用构建器中用于批量渲染重复行数据的核心容器组件:你只需设计一行(包含任意嵌套组件),组件就会根据List data自动复制出多行实例。本篇指南基于当前仓库 listview.md 展开,结合 listview.js 组件配置与 Listview.jsx 运行时代码,完整讲解 List data 绑定、全部属性/事件/暴露变量、分页、样式定制,以及通过children变量用 JS 查询控制子组件,读完即可独立构建"接口数据 → 列表展示 → 行交互"的完整场景。

一、组件定位与核心能力

从组件配置源码 listview.js 可以看出,List View(内部组件名为Listview)本质上是一个带模板子组件的容器

  • 拖入画布时自带 3 个默认子组件:ImageTextButton,分别通过accessorKeyimageURL/text/buttonText)与数据对象的字段自动关联;
  • 默认画布尺寸为宽 15 格、高 450px;
  • 你只编辑第一行模板,组件会按List data的数组长度自动生成后续所有行实例。

与 Container 类似,List View 内部可嵌套任意组件,也支持 List View 嵌套 List View(多级列表)。唯一的限制是:Calendar 和 Kanban 组件被禁止通过拖拽放入 List View 内部

:::caution 受限组件CalendarKanban组件不允许拖入 List View 中使用,请改用其他容器承载它们。 :::

二、设置 List Data:listItem数据绑定

List View 的List data属性接受对象数组返回对象数组的查询结果。在 List View 内部,每一条数据会通过约定变量listItem暴露给行模板中的子组件。

官方文档示例数据:

{{[ { imageURL: 'https://www.svgrepo.com/show/34217/image.svg', text: 'Sample text 1', buttonText: 'Button 1' }, { imageURL: 'https://www.svgrepo.com/show/34217/image.svg', text: 'Sample text 1', buttonText: 'Button 2' }, { imageURL: 'https://www.svgrepo.com/show/34217/image.svg', text: 'Sample text 1', buttonText: 'Button 3' }, ]}}

行内组件的绑定方式:

// Text 组件的 Data 属性 {{listItem.text}} // Image 组件的 source 属性 {{listItem.imageURL}}

从源码看,listItem的注入发生在 Listview.jsx:组件会对过滤后的数据逐条执行filteredData.map((listItem) => ({ listItem })),并通过updateCustomResolvables(id, listItems, 'listItem', ...)注册为自定义可解析变量。这意味着listItem行作用域的——第 0 行的{{listItem.text}}取数组第 0 个元素,第 1 行取第 1 个元素,以此类推。

数据来源的三种方式

方式写法说明
字面量数组{{[{...}, {...}]}}静态数据,适合原型设计
查询结果{{queries.restapi1.data.data}}最常见的动态数据源
JS 表达式{{queries.users.data.map(u => ({...u, fullName: u.first + ' ' + u.last}))}}对查询结果做二次加工

组件配置 listview.js 对data的校验 schema 是「对象数组」或「字符串数组」的联合类型,默认值为[{text: 'Sample text 1'}]——即使留空,组件也有一个可渲染的模板数据。

三、属性详解(Properties)

List View 的全部属性在属性面板中可配置,下表整理了官方属性与源码中的默认值(见 listview.js):

属性说明期望值源码默认值
List data要展示的数据,对象数组或返回对象数组的查询对象数组 / 查询[{text: 'Sample text 1'}]
Mode布局模式,List(单列列表)或Grid(多列网格)list/gridlist
Show bottom border是否显示每行底部分隔线,仅List模式可用true/falsetrue
ColumnsGrid 模式下的列数,仅Grid模式可用任意数值3
Row height每行高度(像素)1–100 之间的数值100
Enable pagination是否启用分页true/falsefalse
Rows per page每页行数,仅启用分页后可用任意数值10

分页的底层实现

从 Listview.jsx 源码可以看到分页是前端切片实现的:

const startIndexOfRowInThePage = currentPage === 1 ? 0 : currentPage * rowPerPageValue - rowPerPageValue; const endIndexOfRowInThePage = startIndexOfRowInThePage + rowPerPageValue; const filteredData = _.isArray(data) ? enablePagination ? data.slice(startIndexOfRowInThePage, endIndexOfRowInThePage) : data : [];

即:enablePaginationtrue时,组件按rowsPerPage对数据做slice分页;rowsPerPage会被强制转成数值(Number(rowsPerPage) ? +rowsPerPage || 10 : 10),非法输入回退到 10。启用分页后,组件底部会渲染一个 Pagination 控件,且组件自身高度会预留约 54px 给分页栏。

Grid 模式与行高

  • Grid 模式下,每行子容器宽度为100 / columns百分比(见 ListviewSubcontainer.jsx),列数小于 1 时会被强制修正为 1(setPositiveColumns);
  • Row height直接作用于每行子容器的高度(height: rowHeight px),超出部分overflow: hidden
  • List 模式下每行宽度为 100%,showBordertrue时在行底绘制1px solid var(--cc-default-border)分隔线。

附加行为属性

除上述属性外,源码中还定义了以下行为开关(位于 Additional Actions 区):

  • Loading statetrue时组件显示 Spinner 加载动画,等待数据就绪(Listview.jsx);
  • Dynamic heighttrue时行高随内容自适应(仅在运行态生效),并会清理行模板的临时布局缓存;
  • Visibility:控制组件可见性;
  • Collapse when hidden:隐藏时是否折叠占位;
  • Disable:锁定组件,禁用交互(通过data-disabled+inert同时阻断鼠标事件与键盘 Tab 焦点);
  • Tooltip:悬停提示(支持 Plain text / Markdown / HTML 三种格式,见 listview.js)。

四、事件(Events)

为 List View 添加事件处理器:点击组件句柄打开右侧属性面板 → 进入Events区 → 点击+Add handler。List View 提供两个事件:

Row clicked(已弃用)

任意一行被点击时触发,可定义多个动作。触发后通过selectedRowIdselectedRow两个变量暴露被点击行的信息(详见下方暴露变量)。

:::warning 弃用提醒Row clicked事件已标记为 deprecated,官方推荐改用Record clicked事件。 :::

Record clicked(推荐)

与 Row clicked 行为一致,点击行内任意记录时触发,并通过selectedRecordIdselectedRecord暴露数据。

从源码 Listview.jsx 看,点击处理统一由onRecordOrRowClicked(index)完成:它同时设置selectedRecordId/selectedRecord/selectedRowId/selectedRow四组暴露变量,并依次触发fireEvent('onRecordClicked')fireEvent('onRowClicked')。事件定义见 listview.js。

值得注意的是,点击发生在捕获阶段onClickCapture,见 ListviewSubcontainer.jsx),因此即便行内子组件自身有点击处理器,List View 的行点击事件也会先行触发。当选中行内的子组件数据后续更新时,listViewComponentSlice.js 还会自动同步刷新selectedRecord/selectedRow的快照,避免出现"点击后数据滞后一行"的问题。

关于可用动作(Actions)的完整说明,请查阅文档站点的 Action Reference 分类文档。

Component Specific Actions(CSA)

目前 List View尚未实现组件级专属动作(CSA),无法通过 JS 查询直接调用如components.listview1.reset()之类的控制方法——对子组件的控制需通过下文第七节的children变量实现。

五、暴露变量(Exposed Variables)

List View 暴露给全局 JS 作用域的变量如下(组件实例名假设为listview1):

变量说明访问方式
data存储加载到组件中的数据(按行索引组织){{components.listview1.data["0"].text1.text}}
selectedRowId(已弃用)被点击行的 ID,从0开始{{components.listview1.selectedRowId}}
selectedRow(已弃用)被点击行内各组件的数据{{components.listview1.selectedRow.text1}}
selectedRecordId被点击记录的 ID,从0开始{{components.listview1.selectedRecordId}}
selectedRecord被点击记录内各组件的数据{{components.listview1.selectedRecord.text1}}
children所有记录内子组件的数据数组用于通过 JS 控制子组件(见第七节)

data 与 children 的生成原理

这两个变量的内容并非手动维护,而是由 store 层 listViewComponentSlice.js 的deriveListviewExposedData自动派生:

  • 遍历 List View 的直接子组件,把每个子组件在当前行的暴露值收集为rowData(对象键为子组件名称,值为{...暴露值, id: 子组件uuid});
  • 写入结构:components.listview1.children[rowIndex]components.listview1.data[rowIndex],其中data是经过deepClone并剥离函数后的纯数据副本——这也是data变量适合被其他组件/查询读取的原因;
  • 每次派生后同步触发依赖更新(updateDependencyValues),保证引用了components.listview1.data的表达式实时重算。

该实现同样支持嵌套 List View:子列表的暴露值通过outerIndices沿外层行索引定位(如components.listview1[0].children表示第 0 行内的嵌套列表),并能正确处理多层嵌套链(_deriveListviewChain)。

行级作用域(Row Scope)机制

listItem绑定与{{components.xxx.value}}行内引用之所以能各取所需,得益于 listViewComponentSlice.js 中的prepareRowScope/updateRowScope

  • 行内子组件(如复选框)的暴露值以按行数组存储(components['checkbox-uuid'] = [{value:false},{value:true},...]);
  • 解析表达式时,引擎用Object.create(components)创建一个以全局组件表为原型的作用域覆盖对象,仅对 List View 的后代组件覆盖为"当前行那一项"(scoped[childId] = val[rowIndex]);
  • 于是{{components.checkbox1.value}}在行 2 内解析到的是{value: true}而不是整个数组。这也解释了为什么同一 List View 内每行的表达式互不干扰。

六、通用属性与样式

Tooltip

General折叠区设置 Tooltip 的字符串内容,鼠标悬停时即显示提示。源码中该配置支持Plain text/Markdown/HTML三种渲染格式(tooltipFormat),默认Plain text

Devices(响应式)

属性说明期望值
Show on desktop桌面端是否显示组件开关按钮,或用fx配置逻辑表达式
Show on mobile移动端是否显示组件开关按钮,或用fx配置逻辑表达式

Styles(样式)

样式说明
Background color背景色,支持 Hex 色值或取色器;源码默认var(--cc-surface1-surface)(跟随主题的表面色)
Border color边框颜色,默认var(--cc-weak-border)
Visibility可见性,仅接受布尔值{{true}}/{{false}},默认{{true}}
Disable禁用组件,仅接受布尔值,默认{{false}}
Border radius圆角,仅接受 1–100 的数值,源码默认6

此外源码还定义了Box shadow(默认0px 0px 0px 0px #00000040)样式项。

:::info 任何带fx按钮的属性都支持编程式配置——点击 fx 后输入{{表达式}},即可在运行态动态取值。 :::

七、控制子组件(Controlling Child Components)

所有行内子组件都通过children变量暴露,它是一个按记录索引的数组,每个元素对应一条记录内各子组件的数据。

你可以用 JS 查询(JavaScript Query)控制行内子组件,例如禁用第一条记录里的button1

components.listview1.children[0].button1.disable(true) // 禁用第 1 条记录中的 button1

:::caution 适用前提 只有实现了组件专属动作(CSA)的子组件才能通过 JS 查询控制。判断某组件是否支持 CSA,请查阅对应组件的文档(组件总览)。 :::

对于支持 CSA 的组件(如按钮的disable/enable/setVisibility等),这一机制让你可以按记录粒度批量操作行内组件——这是 List View 相比普通容器最强大的动态能力之一。

八、完整实操:从 REST API 渲染用户列表

下面复现官方示例,演示一个完整的 List View 数据流。

第 1 步:新建应用并拖入 List View

新建应用,从左侧组件面板把 List View 拖到画布上,此时它处于空列表状态,自带 Image/Text/Button 模板行:

第 2 步:创建 REST API 查询

新建查询,数据源选择REST API,方法选GET,端点填https://reqres.in/api/users?page=1。保存并运行查询,在左侧查看结果,可以看到返回的data对象里是一个对象数组(每项含avatarfirst_nameemail等字段):

第 3 步:绑定 List data

编辑 List View 的List data属性,用 JS 从查询取数:

{{queries.restapi1.data.data}}

这里第一个datarestapi1查询的返回结果,第二个data才是结果中真正承载对象数组的字段。绑定后组件会按数组长度自动生成对应行数的实例:

第 4 步:设计行模板

把组件(文本、图片、按钮等)嵌套进第一行,后续行会自动按第一行的样式复制。行内组件通过listItem取当前行数据:

{{listItem.avatar}} // 示例:展示头像图片 {{listItem.first_name}} // 示例:展示姓名

后续每行会自动套用第一行的布局与数据绑定:

:::tip 在嵌套组件上使用{{listItem.key}}展示数据,其中key是查询结果对象中的字段名。例如示例中用{{listItem.avatar}}显示头像,因为avatar是接口返回对象中的键。 :::

九、源码级注意事项与最佳实践

  • 数据形态校验List data的 schema 要求数组元素为对象或字符串(listview.js)。如果查询返回的不是数组(例如{ data: [...] }结构),请像示例一样补一层.data取到数组本身;
  • 行数变化自动同步:当过滤后的数据行数变化时,Listview.jsx 会通过initExposedValueArrayForChildren为所有子组件初始化/裁剪对应行数的暴露值槽位,并清理children/data中的过期行,因此不需要手动管理行数
  • 大列表性能:行内组件解析采用行级作用域 + 惰性行索引机制(isLazyResolvableParent/getLazyRowIndices,见 componentsSlice.js),Table 的可展开行等场景只解析模板行与当前需要的行,其余按需解析;对普通大列表建议配合分页使用;
  • 嵌套场景:List View 支持在行内再嵌套 List View,listItem与暴露变量会按外层索引正确隔离,多级表达式如{{listItem.orders}}配合内层listItem即可实现主子表结构;
  • 事件选择:新应用请直接使用Record clickedRow clicked仅为向后兼容保留(事件定义中明确标注(Deprecated));
  • 组件约束:Calendar / Kanban 不可拖入 List View;行内组件的 CSA 控制能力取决于该组件自身的实现。

十、相关文档与源码索引

  • 组件官方文档:listview.md(另有 version-3.0.0-LTS 版本 可对照差异)
  • 组件配置与默认值:listview.js
  • 组件运行时实现:Listview.jsx、ListviewSubcontainer.jsx、listview.scss
  • 暴露变量派生与行级作用域:listViewComponentSlice.js
  • listItem解析与惰性行解析:componentsSlice.js
  • 相关测试可参考仓库frontendcypress-tests目录下针对 List View 的用例,验证分页、事件与数据绑定行为。

【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 21:07:38

QT开发入门:QPushButton控件使用全指南

1. QT新手日记005:从零开始掌握QPushButton控件作为一名刚接触QT框架的开发者,我最近在项目中使用QPushButton控件时踩了不少坑。这篇日记记录了我从完全陌生到熟练使用这个基础控件的心路历程,特别适合那些和我一样刚开始接触QT界面开发的朋…

作者头像 李华
网站建设 2026/9/12 21:05:51

Cataclysm DDA 新手生存指南:3 个循环 + 5 条避坑原则

Cataclysm DDA 新手生存指南:3 个循环 5 条避坑原则 【免费下载链接】Cataclysm-DDA Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world. 项目地址: https://gitcode.com/GitHub_Trending/ca/Cataclysm-DDA Catacl…

作者头像 李华
网站建设 2026/9/12 21:04:39

HarmonyOS 首开提速实战:首屏白屏的三种归因与对症方案

本文涉及 HarmonyOS 6.1 / Cloud Foundation Kit(5.0.3(15) 起预加载,6.1.0(23) 起跳链安装预加载)与冷启动时延优化的官方口径。文中的结构、代码示例、决策流程与自检清单为本人整理编写;未在真机逐行验证的部分,请以…

作者头像 李华
网站建设 2026/9/12 21:01:48

STM32+EC200S+4G模块接入阿里云物联网平台实战

简介:面向采用STM32F103单片机的开发者,这套4G DTU方案使用EC200S模块接入阿里云物联网平台,基于MQTT协议定时上传温度数据,同时接收并解析平台返回的JSON指令,完成LED灯的远程控制,覆盖感知、传输、云平台…

作者头像 李华