
NocoBase 如何用 RunJS 编写 JS 区块、JS 字段和 JS 操作【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase如果你需要在 NocoBase 的某个页面里加一段自定义渲染、自定义字段展示或自定义按钮逻辑又不想创建插件或改源码可以用 RunJS在界面搭建器里直接写 JavaScript代码运行在受限沙箱中通过ctx上下文访问数据、发起请求、打开视图并渲染内容。本文覆盖 RunJS 的三个主要落点——JS 区块、JS 字段、JS 操作给出各自的适用位置、上下文能力和可直接运行的代码示例。适用前提是你能进入对应页面/区块的界面搭建器或表单的字段编辑界面。三个场景各解决什么问题RunJS 在界面搭建中的扩展位置不止三种其中与本文相关的三类是JS 区块自定义渲染一整个区块可完全控制区块结构与样式适合展示自定义组件、统计图表、第三方内容等JS 字段在字段位置自定义渲染内容常见于详情区块、表单只读项或表格列中的自定义项可按字段值动态显示不同样式、内容或状态JS 操作自定义操作按钮的点击逻辑可执行任意前端操作或 API 请求例如动态计算、提交自定义数据、触发弹窗。它们共用同一套脚本编辑器支持语法高亮、错误提示和内置代码片段Snippets可搜索并一键插入到光标位置点击Run可以直接运行当前代码运行日志输出到底部Logs面板支持console.log/info/warn/error错误会高亮并可定位到具体行列。写脚本时先Run验证、再挂到正式视图是文档给出的调试方式。运行环境能写什么、不能写什么在写三种场景的代码前先明确 RunJS 的执行环境见 RunJS 概述沙箱脚本在受控环境中运行window、document、navigator采用安全代理对象常见 API 可用、风险行为受限顶层await支持顶层异步无需包裹 IIFE。推荐直接写await test();而不是asyncIIFE 包一层导入模块ESM 模块用ctx.importAsync()推荐UMD/AMD 模块用ctx.requireAsync()容器内渲染用ctx.render()将 JSX、DOM 节点或 HTML 字符串渲染到当前容器ctx.element全局变量window、document、navigator、ctx。JS 区块和 JS 字段的脚本还有两条运行特性需要注意容器ctx.element是安全封装的 ElementProxy仅影响当前区块/字段不干扰页面其它区域区块被隐藏后再显示会自动重渲染。因此绑定事件前应清理或去重“先 remove 再 add”、一次性监听器或加标记防重复避免重复触发。编写 JS 区块在页面或弹窗中添加 JS Block 后即可在其脚本编辑器中编写代码。JS 区块的运行时上下文已注入常用能力可直接使用完整说明见 JS Block 区块ctx.element区块的 DOM 容器支持innerHTML、querySelector、addEventListener等ctx.requireAsync(url)/ctx.importAsync(url)异步加载 UMD/AMD 库 / 动态导入 ESM 模块ctx.openView打开已配置视图弹窗/抽屉/页面ctx.useResource(...)ctx.resource以资源方式访问数据ctx.i18n.t()/ctx.t()国际化ctx.onRefReady(ctx.ref, cb)容器就绪后再渲染避免时序问题ctx.libs.React/ctx.libs.ReactDOM/ctx.libs.antd/ctx.libs.antdIcons/ctx.libs.dayjs/ctx.libs.lodash/ctx.libs.math/ctx.libs.formula内置通用库ctx.render(vnode)将 React 元素、HTML 字符串或 DOM 节点渲染到默认容器ctx.element多次调用会复用同一 React Root并覆盖容器现有内容。文档给出的常用写法示例// 渲染 ReactJSX const { Button } ctx.libs.antd; ctx.render( div style{{ padding: 12 }} Button typeprimary onClick{() ctx.message.success(ctx.t(Clicked!))} {ctx.t(Click)} /Button /div );// API 请求模板 const resp await ctx.api.request({ url: users:list, method: get, params: { pageSize: 10 } }); ctx.message.success(ctx.t(Request finished)); console.log(ctx.t(Response data:), resp?.data);加载外部图表库的例子文档示例https://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js为文档给出的 CDN 地址// 加载 ECharts 并渲染 const container document.createElement(div); container.style.height 360px; container.style.width 100%; ctx.element.replaceChildren(container); const echarts await ctx.requireAsync(https://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js); if (!echarts) throw new Error(ECharts not loaded); const chart echarts.init(container); chart.setOption({ title: { text: ctx.t(ECharts) }, xAxis: {}, yAxis: {}, series: [{ type: bar, data: [5, 12, 9] }] }); chart.resize();打开抽屉视图的示例ctx.model.uid是当前模型文档以此拼出视图 uidconst popupUid ctx.model.uid -1; await ctx.openView(popupUid, { mode: drawer, title: ctx.t(Sample drawer), size: large });编写 JS 字段JS Field 用于在字段位置以 JavaScript 自定义渲染内容完整说明见 JS Field。它有明确的两种类型选择时要区分只读型用于不可编辑展示读取ctx.value渲染输出。适用位置详情区块展示计算结果、状态徽章、富文本片段、图表等只读内容表格区块中作为“其他自定义列 JS Field”只读展示若需要不绑定字段的列用 JS Column可编辑型用于自定义输入交互提供ctx.getValue()/ctx.setValue(v)与容器事件js-field:value-change与表单值双向同步。适用位置表单区块CreateForm/EditForm中的自定义输入控件或复合输入随表单校验与提交例如外部库输入组件、富文本/代码编辑器、复杂动态组件。JS Field 的运行时上下文与 JS 区块大体一致ctx.element、ctx.value、ctx.record、ctx.collection、ctx.requireAsync、ctx.importAsync、ctx.openView、ctx.i18n.t()/ctx.t()、ctx.onRefReady、ctx.libs.*、ctx.render其中ctx.value、ctx.record、ctx.collection为只读。可编辑型额外提供ctx.getValue()获取当前表单值优先使用表单状态再回退到字段 propsctx.setValue(v)设置表单值与字段 props保持双向同步容器事件js-field:value-change外部值变化时触发便于脚本更新输入显示。文档给出的示例// 基础渲染读取字段值 ctx.render(span classNamenb-js-field{String(ctx.value ?? )}/span);// 使用 JSX 渲染 React 组件按字段值切换标签颜色 const { Tag } ctx.libs.antd; ctx.render( div style{{ padding: 4 }} Tag color{ctx.value ? green : default}{String(ctx.value ?? )}/Tag /div );可编辑型字段示例渲染一个简单输入并同步表单值ctx.element.addEventListener(js-field:value-change, ...)部分为文档标注的可选逻辑function InputView() { return ( input classNamenb-js-editable style{{ width: 100%, padding: 4px 8px }} defaultValue{String(ctx.getValue() ?? )} onInput{(e) ctx.setValue(e.currentTarget.value)} / ); } // 外部值变化时同步到输入可选 ctx.element.addEventListener(js-field:value-change, (ev) { const el ctx.element.querySelector(.nb-js-editable); if (el) el.value ev.detail ?? ; }); ctx.render(InputView /);JS 字段文档同样建议外部库加载使用可信 CDN并为失败场景做兜底如if (!lib) return;选择器优先用class或[name...]避免固定id字段可能因数据变化或视图切换而多次重渲染绑定事件前先清理或去重。编写 JS 操作JS Action 用于按钮点击时执行 JavaScript自定义任意业务行为。可放置在表单工具栏、表格工具栏集合级、表格行记录级等位置实现校验、提示、接口调用、打开弹窗/抽屉、刷新数据等操作完整说明见 JS Action。按钮位置不同上下文变量也不同文档给出的常见能力概览ctx.api.request(options)发起 HTTP 请求ctx.openView(viewUid, options)打开已配置的视图抽屉/对话框/页面ctx.message/ctx.notification全局提示与通知ctx.t()/ctx.i18n.t()国际化ctx.resource集合级上下文的数据资源如表格工具栏含getSelectedRows()、refresh()等ctx.record记录级上下文的当前行记录如表格行按钮ctx.form表单级上下文的 AntD Form 实例如表单工具栏按钮ctx.collection当前集合元信息ctx.requireAsync(url)/ctx.importAsync(url)与ctx.libs.*内置库。文档特别注明实际可用变量会随按钮所在位置不同而有所差异以上为常见能力概览。按位置对应的示例// 接口请求与提示 const resp await ctx.api.request({ url: users:list, method: get, params: { pageSize: 10 } }); ctx.message.success(ctx.t(Request finished)); console.log(ctx.t(Response data:), resp?.data);// 集合按钮校验选择并处理 const rows ctx.resource?.getSelectedRows?.() || []; if (!rows.length) { ctx.message.warning(ctx.t(Please select records)); return; } // TODO: 执行业务逻辑… ctx.message.success(ctx.t(Selected {n} items, { n: rows.length }));// 记录按钮读取当前行记录 if (!ctx.record) { ctx.message.error(ctx.t(No record)); } else { ctx.message.success(ctx.t(Record ID: {id}, { id: ctx.record.id })) }// 打开视图抽屉/对话框uid 绑定到当前按钮以保持行为稳定 const popupUid ctx.model.uid -open; await ctx.openView(popupUid, { mode: drawer, title: ctx.t(Details), size: large });// 提交后刷新数据优先表格/列表资源其次表单所在区块资源 if (ctx.resource?.refresh) await ctx.resource.refresh(); else if (ctx.blockModel?.resource?.refresh) await ctx.blockModel.resource.refresh();JS 操作文档列出的注意事项避免重复点击导致多次提交加状态开关或禁用按钮为接口调用添加 try/catch 并给出用户提示通过ctx.openView打开弹窗/抽屉时建议显式传参必要时在提交成功后主动刷新父级资源。JSX 写法要点上面示例中的Button、Tag等 JSX 由 RunJS 自动编译用 sucrase 转换编译为ctx.libs.React.createElement和ctx.libs.React.Fragment因此无需import React直接写 JSX 即可详见 RunJS JSX 语法。内置可用库ctx.libs.React— React 本体ctx.libs.ReactDOM— ReactDOM如需可配合 createRoot 使用ctx.libs.antd— Ant Design 组件ctx.libs.antdIcons— Ant Design 图标。两条规则需要遵守直接写 JSX 时无需解构 React只有使用 Hooks如useState、useEffect或 Fragment.../时才需要const { React } ctx.libs;const { React } ctx.libs; const { useState } React; const Counter () { const [count, setCount] useState(0); return divCount: {count}/div; }; ctx.render(Counter /);内置 React 与通过ctx.importAsync()导入的外部 React不能混用。若使用外部 UI 库React 也需从外部一并导入且用deps指定同一版本避免多实例文档示例const React await ctx.importAsync(react18.2.0); const { Button } await ctx.importAsync(antd5.29.3?bundledepsreact18.2.0,react-dom18.2.0); ctx.render(ButtonButton/Button);JSX 语法要点表达式用{表达式}插入变量或运算如{ctx.user.name}不要使用{{ }}模板语法条件渲染用{flag span内容/span}或三元表达式列表渲染用array.map()并设置稳定的key。通用注意事项三类场景共享的限制与约定外部库加载建议使用可信 CDN并为加载失败做兜底选择器优先使用class或[name...]属性选择器避免固定id防止多个区块/弹窗中出现重复id导致样式或事件冲突脚本可能多次重渲染绑定事件前先清理或去重“先 remove 再 add”、一次性监听器或加标记JS 操作要保证行为幂等避免重复点击导致多次提交所有代码都先用编辑器的Run在Logs面板验证行为与错误定位再放入正式视图。RunJS 定位是轻量扩展方式适合快速实验和临时逻辑处理若同一套能力被文档列出但与本文无关的场景JS 项、JS 表格列、联动规则、事件流可在 在线编写 运行 JS 的索引中找到对应文档。【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考