ToolJet 多页面应用(Pages)完整指南:页面面板、页面选项与页面变量实战
ToolJet 多页面应用(Pages)完整指南:页面面板、页面选项与页面变量实战
ToolJet 允许在单个应用中创建多个页面,把复杂的业务工具拆分为更易导航、更友好的多页应用。本文以 pages.md 为骨架,结合仓库内 switch-page、set-page-var、unset-page-var 等动作文档及前端 pageMenuSlice.js 源码,系统讲解页面面板的操作、页面级选项、暴露变量(Exposed Variables)以及跨页面数据传递的完整实战方案。读完本文,你将掌握在 ToolJet 中创建与管理多页应用、配置页面导航、使用 {{page.*}} 变量以及通过事件与 RunJS 在页面间传参的全部能力。
页面面板(Pages Panel)
在 ToolJet 应用构建器(App Builder)中,页面面板是管理多页应用的入口。点击应用构建器左侧边栏中的 Pages 图标即可打开面板。
从源码结构看,页面面板相关的界面与逻辑集中在 frontend/src/AppBuilder/AppCanvas/PageMenu 目录与 frontend/src/AppBuilder/RightSideBar/PageSettingsTab/PageMenu 目录中,页面列表、首页标识、隐藏与禁用状态等状态则由 pageMenuSlice.js 这一 Zustand store slice 统一管理。
面板选项(Panel Options)
添加页面(Add Page)
- 在页面面板头部找到 + 按钮。
- 点击 + 按钮添加一个新页面。
- 输入新页面的名称并按回车确认。
新建页面时页面名称会同时用于生成默认的页面句柄(Page Handle,见下文),该逻辑在 AddNewPagePopup.jsx 中实现。
设置(Settings)
点击设置按钮后,右侧会打开一个新面板,用于自定义应用内的页面导航侧边栏,包含两个标签页:
Properties 标签页
| 选项 | 说明 |
|---|---|
| Collapsable(可折叠) | 使页面导航侧边栏可折叠/展开 |
| Style(样式) | 选择页面导航侧边栏的显示方式:仅文本(Text only)、文本+图标(Text + icon)或仅图标(Icon only) |
| Hide page menu in viewer mode(在查看器模式隐藏页面菜单) | 在查看器(Viewer)模式下隐藏页面导航侧边栏 |
Style 标签页
Style 标签页用于自定义页面导航侧边栏的外观样式,例如字体、颜色、间距等视觉属性。
固定面板(Pin)
默认情况下,当你在面板外部点击时,页面面板会自动关闭。点击 Pin 按钮可以固定页面面板,固定后面板不会关闭,直到你再次取消固定(unpin)。
页面选项(Page Options)
每个页面卡片右侧都有一个 kebab 菜单(三个点的菜单按钮),点击后可以看到该页面的全部操作选项。
页面句柄(Page Handle)
Page Handle 是追加在应用 URL 末尾的 slug。默认情况下,页面句柄是页面名称的小写形式,并将空格替换为连字符。你可以点击页面句柄旁边的 Edit 符号来修改它。
例如在 URL https://app.tooljet.ai/applications/crm2/home 中,crm2 是应用名,home 就是页面句柄。句柄可以直接用于 Switch Page 动作与 {{page.handle}} 表达式中(详见下文)。
重命名(Rename)
Rename 选项允许你重命名页面。注意:重命名页面不会改变 slug/页面句柄,二者相互独立。
标记为首页(Mark Home)
Mark home 选项可以将某个页面设为应用的默认落地页。打开应用时,被标记为 home 的页面将是第一个展示的页面。在源码中,首页信息记录在应用数据的 homePageId 字段上(见 pageMenuSlice.js 中的相关状态更新逻辑)。
在应用菜单中隐藏页面(Hide Page on app menu)
Hide Page 选项可以将页面从查看器模式的 页面导航侧边栏 中隐藏。之后你可以再次打开该选项并 取消隐藏(unhide) 该页面。
注意:
- 被标记为 home 的页面不能被隐藏。
- 隐藏页面后,虽然页面不再出现在导航侧边栏中,但仍可通过 switch page 动作 或直接访问 页面 URL 来打开它。
复制页面(Duplicate)
Duplicate 选项可以在页面列表中创建并添加一个原页面的副本,复制出的页面将是原页面的精确复制品(exact replica)。
事件处理器(Event Handlers)
与其他 ToolJet 组件一样,页面也可以附加事件处理器。页面提供 On page load 事件。该事件可以使用所有可用的动作,此外还包含专门为页面新增的三个动作:
这三个动作分别对应前端 store 中的页面切换与页面变量读写逻辑,实现细节见 pageMenuSlice.js 以及 events 相关 slice。
禁用页面(Disable Page)
Disable Page 选项可以禁用某个页面。被禁用的页面在查看器模式下将不可访问。
注意:被标记为 home 的页面不能被禁用。
删除页面(Delete Page)
你可以使用该选项从应用中删除页面。
注意:被标记为 home 的页面不能被删除。
暴露变量(Exposed Variables)
每个页面都暴露了以下可在表达式中动态访问的变量:
| 变量 | 说明 |
|---|---|
| handle | 页面在应用内的 slug。在 URL https://app.tooljet.ai/applications/crm2/home 中,crm2 是应用名,home 是句柄。句柄在添加页面时自动设置,也可以通过页面选项重命名。动态访问方式:{{page.handle}} |
| name | 创建页面时设置的页面名称。动态访问方式:{{page.name}} |
| id | 每个页面在创建时获得的唯一标识符。动态访问方式:{{page.id}} |
| variables | 一个对象,包含通过 Set Page Variable 动作为该页面创建的所有变量。访问某个具体变量的值:{{page.variables.<pageVariableName>}},其中 <pageVariableName> 是创建变量时指定的名称 |
这些变量在构建器的表达式求值环境中可用(相关实现见 frontend/src/AppBuilder/_stores/slices/resolvedSlice.js 与 appSlice.js)。
页面专属动作详解
Switch Page(切换页面)
利用 Switch Page 动作,可以在多页应用的事件处理器中跳转到另一个页面。默认情况下防抖(debounce)字段留空,你也可以输入一个数值,表示动作执行前的等待毫秒数,例如 300。
Query Params(查询参数)
查询参数可以通过 Switch Page 这类动作传递,参数会追加到应用 URL 的末尾,并以问号(?)开头。查询参数由键值对组成,key 和 value 之间用等号(=)分隔,可以通过点击 + 按钮添加多个查询参数。
例如,设置 username 为 key,值为 {{globals.currentUser.email}},即可动态获取当前登录用户的邮箱。点击触发 Switch Page 事件的按钮后,被切换到的页面 URL 中将携带这些参数。查询参数常用于向服务器提供附加信息或修改网页行为,例如过滤搜索结果、分页、排序等。
通过 RunJS 查询切换页面
Switch Page 动作也可以通过 RunJS 查询触发,语法如下:
await actions.switchPage('<page-handle>')
带查询参数切换页面
actions.switchPage('<pageHandle>', [['param1', 'value1'], ['param2', 'value2']])
关于如何从 RunJS 查询中运行动作,可参考指南 Running Actions from RunJS Query。
从前端源码看,页面切换由 store 暴露的 switchPage 相关方法驱动(见 MobileNavigationMenu.jsx 中的 switchPageWrapper 调用链),页面导航侧边栏与移动端菜单均复用了同一套切换逻辑。
Set Page Variable(设置页面变量)
页面变量(Page variables)仅限于创建它的页面内使用,与整个应用内可访问的普通变量不同。使用该动作可以在多页应用中建立变量并赋值。
默认情况下防抖字段留空,可以输入毫秒数值指定延迟执行,例如 300。
通过 RunJS 查询设置页面变量
await actions.setPageVariable('<variablekey>', <variablevalue>)
其中 variablekey 必须作为字符串提供(用引号包裹),而 variablevalue 如果是数值则不需要引号。
设置完成后,可通过 {{page.variables.<variablekey>}} 在表达式、组件属性或查询中读取该值。
Unset Page Variable(清除页面变量)
利用该动作可以清除通过 set page variable 动作 建立的变量。默认防抖字段同样留空,可输入毫秒数值指定延迟。
通过 RunJS 查询清除变量
await actions.unsetPageVariable('<variablename>')
其中 variablename 是创建变量时提供的变量 key。
实战一:在页面加载时使用 URL 参数(URL Params on Load)
URL 参数用于在页面之间传递数据。目前可以通过以下两种方式添加 URL 参数:
- 通过 Switch page 动作(从事件中)
- 通过 JavaScript 代码查询 中的代码
如果页面带 URL 参数打开,你可以使用 {{globals.urlparams}} 访问它们。该对象包含所有 URL 参数的键值对,使用 {{globals.urlparams.<parameter_name>}} 可访问具体参数。
在页面加载时用 URL 参数执行 REST API 查询
下面通过完整示例演示如何利用 URL 参数在页面加载时触发 REST API 查询。
第一步:创建两个页面
新建应用后默认会有一个名为 Home 的页面。从左侧边栏的 Pages 菜单新建一个名为 Dashboard 的页面。
第二步:搭建 Home 与 Dashboard 页面
- 在
Home页面添加一个 Form 组件,包含一个文本输入框和一个按钮。将文本输入框命名为email,按钮命名为Submit。 - 选中按钮,添加
On click事件,选择Switch page动作并选择目标页面Dashboard。在该动作中可以添加 URL 参数:添加参数email,值设为{{components.form1.data.textinput1.value}}。这样就把邮箱输入框的值作为 URL 参数传递到Dashboard页面。
点击 Submit 按钮后,Dashboard 页面将携带参数 email(值为邮箱输入框内容)打开。你可以打开左侧边栏的 Inspector,导航到 globals 下的 URL Params 查看这些参数。
第三步:创建查询并绑定数据
在 Dashboard 页面添加两个表格组件,分别绑定两个 REST API 查询返回的数据:
- Query 1: Get Products:创建 REST API 查询并命名为
products,URL 为https://fakestoreapi.com/products。运行查询并预览返回数据后,将table1的表数据属性设为{{queries.products.data}}。 - Query 2: Get User Details:创建 REST API 查询并命名为
users,URL 为https://jsonplaceholder.typicode.com/users。运行后,将table2的表数据属性设为{{queries.users.data}}。 - Query 3: JavaScript Code To Use URL Parameters:创建一个 JavaScript 代码查询并命名为
urlparams,用于检查 URL 中是否存在email参数,若存在则触发上述两个 REST API 查询:
function waitForURLParams(timeout) { // 等待 URL 参数可用
const check = resolve => { // 检查 URL 参数是否可用
if (location.search.length > 0) resolve(); // URL 参数已可用
else setTimeout(_ => check(resolve), timeout); // 超时后再次检查
}
return new Promise(check); // 返回一个在 URL 参数可用时 resolve 的 Promise
}
async function checkAndRunQuery(timeout) { // 检查 URL 参数是否可用并运行 REST API 查询
await waitForURLParams(timeout); // 等待 URL 参数可用
const urlParams = new URLSearchParams(window.location.search); // 获取 URL 参数
if (urlParams.get('email')) { // 检查 URL 中是否存在 email 参数
await actions.runQuery('products'); // 运行 REST API 查询获取产品数据
await actions.runQuery('users'); // 运行 REST API 查询获取用户详情
}
else {
alert('URL param not found'); // 若 email 参数不存在则弹出提示
}
}
checkAndRunQuery(5000); // 在 5 秒超时后检查 URL 参数并运行 REST API 查询
第四步:配置 Dashboard 页面事件处理器
最后,回到左侧边栏的 Pages 菜单,打开 Dashboard 页面的菜单,添加事件处理器:选择 On page load 事件,选择 Run query 动作,并选择查询 urlparams。这样每次 Dashboard 页面加载时,都会执行上述 JavaScript 查询——检查 URL 中是否存在 email 参数,若存在则运行 REST API 查询并填充表格数据。
实战二:在 Listview 记录点击后于新页面展示详情
多页应用还常用于"列表页 → 详情页"的模式。以下示例演示如何在点击 Listview 组件中的记录后,在另一个页面展示该记录的详细信息。
第一步:搭建应用
- 拖入一个 Listview 组件并配置好所需的其他组件。
- 在应用中添加另一个页面。
- 在第二个页面中配置需要的字段与组件。
第二步:设置事件处理器
为 Listview 组件添加事件处理器,配置如下:
- 事件:Record Clicked
- 动作:Set variable
- Key:
selectedEmp(可换成你想要的变量名) - Value:
{{[{
name: components.listview1.selectedRecord.text17.text,
designation: components.listview1.selectedRecord.text15.text,
department: components.listview1.selectedRecord.text14.text
}]}}
该事件会把记录值保存到指定变量中,供其他页面访问。
再创建第二个事件:
- 事件:Record Clicked
- 动作:Switch page
- Page:Employee Details(从下拉框选择目标页面)
该事件会在记录被点击时切换页面。
第三步:在另一个页面展示信息
现在你可以引用上一页面变量中存储的值。例如,将 Text input 组件的默认值设置为:
{{variables.selectedEmp[0].name}}
即可在详情页显示被点击记录的姓名。
常见问题与要点速查
- 页面句柄与页面名称:重命名页面不会改变句柄;句柄需要单独编辑。句柄是 URL slug,也是
Switch Page动作与{{page.handle}}表达式的依据。 - 首页(Home)约束:被标记为 home 的页面不能被隐藏、禁用或删除。
- 隐藏页面的可达性:隐藏页面只是从导航侧边栏消失,通过 Switch Page 动作或直接访问页面 URL 仍然可以打开。
- 页面变量作用域:通过 Set Page Variable 创建的变量仅在创建它的页面内有效,跨页面请使用普通变量(如
Set variable动作)或 URL 参数。 - URL 参数访问:页面加载时可通过
{{globals.urlparams.<key>}}读取;事件传递时在 Switch Page 动作中添加键值对即可。 - RunJS 触发页面动作:
actions.switchPage、actions.setPageVariable、actions.unsetPageVariable均可从 RunJS/JavaScript 代码查询中调用,语法与示例见上文。
通过以上内容,你已经可以在 ToolJet 中构建出结构清晰、导航友好、支持跨页传参的多页面应用。更进一步,可以结合 On Page Load 事件 与 Switch Page 动作,设计从列表到详情、从表单到结果页的完整业务流。






