ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LowCodeEngine 实战:从拖拽到事件回调,一步步搭建动态查询表格页

LowCodeEngine 实战:从拖拽到事件回调,一步步搭建动态查询表格页 LowCodeEngine 实战从拖拽到事件回调一步步搭建动态查询表格页【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine本文基于 LowCodeEngine 官方文档《如何制作表格》(docs/docs/demoUsage/makeStuff/table.md) 展开完整继承原文的“拖入组件 → 配置组件 → 绑定数据 → 动态请求 → 配置插槽 → 列挂钩浮层 → 事件回调”七步实操脉络并结合 renderer-core 的渲染器源码packages/renderer-core/src/renderer/base.tsx与低代码协议规范docs/docs/specs/lowcode-spec.md解释每一步操作最终写进了 Schema 的什么字段、运行时又是如何被解析执行的。读完本文你可以独立完成一个带动态数据请求、Loading 状态和操作列弹窗的后台表格页并能看懂其背后的 Schema 结构与渲染器生命周期执行机制。一、页面结构查询框 表格 分页一个常见的后台表格页面由三类组件构成查询框查询筛选、表格和分页按钮。这些组件在 Fusion UIFusion Next中已有对应封装可以直接在 LowCodeEngine 左侧组件面板中找到并拖入画布。原文档给出的完整操作是在左侧组件面板中找到“查询筛选”“表格”“分页”等组件依次拖拽到画布中形成页面骨架后续所有操作都围绕这三类组件的属性配置与数据绑定展开。这一步没有代码参与但它决定了最终页面树在 Schema 中的节点结构——每个被拖入的组件都会在 Schema 中生成一个包含componentName、id、props等字段的节点后续的配置和绑定都是对这个节点的改写。二、配置组件理解 Array 类型配置项选中刚拖入的“查询筛选”组件右侧设置器面板会列出它的可配置属性。原文档特别强调了一个高频操作模式对于形如 Array 的配置项目我们可以增删项目、修改常用项、修改顺序。掌握这一点后就可以完成一个常用查询框的字段配置比如选择“公司名称”“创建时间”等查询字段。从源码结构看设置器面板对每种属性值类型有对应的 setter设置器实现Array 类型的 setter 支持列表式的增删与排序操作而“常用项”的修改则走标量型 setter。这些属性值最终都会写入 Schema 节点props下对应的 key成为纯静态配置与后文的动态数据形成对比。三、绑定数据把 state 表达式注入组件属性低代码场景的核心是动态数据。原文档给出了两步第一步在源码面板创建动态数据。通过左侧源码编辑面板把如下自定义值配置进statecompanies: [ { company: 测试公司1, id: 1, createTime: new Date() }, { company: 测试公司2, id: 2, createTime: new Date() }, { company: 测试公司3, id: 3, createTime: new Date() } ]第二步把动态数据绑定到组件属性上。找到表格数据源相关属性的配置项输入表达式this.state.companies这一步完成后表格主体就能渲染出三行测试数据。3.1 表达式在 Schema 中长什么样源码面板文档docs/docs/demoUsage/panels/code.md明确了变量绑定写入 Schema 后的标准形态{ componentName: NextBlockCell, id: node_ockzmje8tf5, props: { bodyPadding: { type: JSExpression, value: this.state.text, mock: } } }也就是说“绑定this.state.companies”这个动作本质是在节点属性上写了一个type: JSExpression的值。value是表达式字符串mock字段用于设计态画布下没有真实运行时上下文时的兜底展示。3.2 渲染器如何执行这个表达式设计态的预览由渲染器完成。在 packages/renderer-core/src/renderer/base.tsx 中渲染器基类在构造函数里装配了表达式解析器this.__parseExpression (str: string, self: any) { return parseExpression({ str, self, thisRequiredInJSE: props?.thisRequiredInJSE, logScope: props.componentName }); };运行时对JSExpression类型属性求值时就是调用parseExpression实现位于 packages/renderer-core/src/utils/common.ts把this指向渲染器实例从而让this.state.companies能真正解析到当前组件的状态。而this.state、this.setState以及this.context.appHelper.utils、this.context.appHelper.requestHandlerMap等成员正是源码面板文档中列出的“局部变量引用”清单——它们保证了你在源码面板里写出的代码与渲染器实例的成员是一一对应的。3.3 源码面板的读写与保存机制源码面板文档还说明了本步骤依赖的读写规则读取每次打开面板时优先读取 Schema 中的originCode字段如果没有则从 Schema 上的字段state、生命周期、方法等还原代码写入关闭面板点叉或点击非编辑区或点击“保存”时代码会被解析并写回 Schema异常处理代码解析失败时无法保存编辑器会弹层提示。需要留意的限制面板依赖 Babel 编译但编译结果受babel/runtime干扰目前不支持async await或{ ...arr }形态语法的编译。本文后续动态请求示例刻意使用fetch().then()链式写法正是为了绕开这一限制。四、动态请求用生命周期方法接入真实接口原型数据跑通后把数据源换成真实接口。原文档假设接口地址为http://rap2api.taobao.org/app/mock/250089/testCompanies示例用 Mock 地址实操中替换为你自己的接口在源码面板中配置class LowcodeComponent extends Component { state { text: outer, isShowDialog: false, loading: false, companies: [ { company: 测试公司 1, id: 1, createTime: new Date() }, { company: 测试公司 2, id: 2, createTime: new Date() }, { company: 测试公司 3, id: 3, createTime: new Date() } ] } componentDidMount() { this.setState({ loading: true }) window.fetch(http://rap2api.taobao.org/app/mock/250089/testCompanies) .then((res) res.json()) .then((companies) { this.setState({ companies, }) }) .catch(err console.error(err)) .then(() { this.setState({ loading: false }) }) } }要点在componentDidMount生命周期内发起请求先置loading: true请求成功后setState更新companies无论成败最后在.then收尾处复位loading: false注意这里用链式.then而非finally与catch后的链式顺序保证一致;点击保存或关闭源码面板后代码即刻生效画布会按新数据重新渲染。4.1 componentDidMount 的底层执行链路这段代码为什么能“生效”渲染器基类在 packages/renderer-core/src/renderer/base.tsx 中实现了生命周期转发async componentDidMount(...args: any[]) { this.reloadDataSource(); this.__executeLifeCycleMethod(componentDidMount, args); this.__debug(componentDidMount - ${this.props?.__schema?.fileName}); }其中__executeLifeCycleMethod同文件 L250-L252会取出当前节点的 Schema调用executeLifeCycleMethod(this, this.props.__schema, componentIdMount, ...)定位到lifeCycles.componentDidMount对应的JSFunction并执行this仍指向渲染器实例因此你在源码里写的this.setState直接作用在同一个实例上。这一点也与协议规范吻合docs/docs/specs/lowcode-spec.md 定义了组件的lifeCycles对象其 key 就是标准 React 生命周期方法名lifeCycles: { componentDidMount: { type: JSFunction, value: function componentDidMount(){ ... } } }规范中列出的支持方法包括constructor、componentDidMount、componentDidUpdate、componentWillUnmount、componentDidCatch等。也就是说源码面板里那段class LowcodeComponent的写法最终被拆解为 Schema 上的state初始值 lifeCyclesmethods三块结构再由渲染器在恰当的 React 生命周期点重新组装执行。另外注意componentDidMount中还隐式执行了reloadDataSource()base.tsx L214-L230如果页面配置了数据源DataSource渲染器会在挂载后自动拉取初始数据并setState。本文示例用fetch手动管理数据是为了演示最直接的动态请求写法从源码结构看两者可结合使用但手动请求对加载时序的控制更直观。五、配置插槽把 Loading 与内容组织起来原文档的第五步将 Loading 组件的“是否显示”字段绑定this.state.loading即可看到请求过程中的加载指示。这一步同时引入了**插槽Slot**概念表格组件暴露了若干可任意扩展的预设区域你可以把其他组件拖进插槽中——例如把 Loading、分页等放进表格的对应插槽位置而不是平铺在页面根层级。从 Schema 视角看插槽与组件节点是等价的拖入插槽的组件同样生成componentName/id/props节点只是父节点关系挂在了插槽对应的容器节点之下。插槽机制让“表格 分页 加载态”这类组合在组件结构上保持内聚也解释了为什么分页按钮不需要额外处理与表格的相对布局。完成插槽配置后点击预览即可看到完整的动态请求效果进入页面时 Loading 出现接口返回后表格填充数据、Loading 消失。六、列挂钩浮层操作列的弹窗行为为了让表格“操作列”能弹出浮层原文档的操作序列是拖入一个浮层Dialog到画布浮层默认可能遮挡视线使用大纲树面板可以临时显示/隐藏它给表格增加一个数据列例如“操作”列将该列的行为配置为“弹窗”即绑定到刚拖入的浮层。完成后点击表格行内的操作入口对应的浮层会弹出实现“行级操作 → 详情浮层”的常见交互。这一步全部是配置态操作没有写任何代码列的“行为 弹窗”本质上是一个预设了事件关联关系的复合属性由组件物料内部完成浮层可见性的控制。大纲树在这里的价值在于管理“暂时不可见节点”——浮层这类组件不展开时画布上看不到但它始终存在于 Schema 树中。七、事件回调把操作行为绑到操作列按钮前六步把“弹窗”行为绑在数据列上原文档最后演示了更细粒度的做法——把行为绑到操作列的具体按钮上在操作列按钮处点击“添加一项”新增一个按钮点击按钮配置项下方的详情配置其事件回调在源码侧实现对应的回调函数onClick_new(e, { rowKey, rowIndex, rowRecord }){ window.Next.Message.show(JSON.stringify({ rowKey, rowIndex, rowRecord })) }保存后预览点击按钮会弹出一条 Message内容是当前行的rowKey、rowIndex与rowRecord。这演示了低代码表格页最重要的能力之一事件回调能拿到行级上下文从而支持“对当前行执行删除/编辑”这类操作。7.1 事件回调在 Schema 中的落地形态源码面板文档给出了事件绑定写入 Schema 的完整样例docs/docs/demoUsage/panels/code.md{ componentName: Filter, id: node_ockzmj0cl11w, props: { __events: { eventDataList: [ { type: componentEvent, name: onSearch, relatedEventName: closeDialog } ] }, onSearch: { type: JSFunction, value: function(){this.onSearch.apply(this,Array.prototype.slice.call(arguments).concat([])) } } } }结构解读__events.eventDataList记录设计态的“事件绑定关系”哪个事件名关联到哪个用户方法供设置器面板回显与编辑真正运行时执行的属性如onSearch是一个JSFunction其value是一个代理函数——它把参数数组原样透传后apply到用户方法this.onSearch上。本文示例中的onClick_new走同样的机制渲染器执行代理函数时把e与{ rowKey, rowIndex, rowRecord }透传给源码里定义的同名方法。7.2 关于window.Next.Message.show回调里使用的window.Next.Message.show(...)依赖资产包以 UMD 方式引入 Fusion Next 后的全局变量。源码面板文档明确说明代码中可以通过window引用全局变量若引入了 Fusion NextDemo 默认引入即可直接调用window.Next.Message.success(成功)这类 API。本文示例的window.Next.Message.show属于同一模式。八、总结与延伸回顾七步可以抽象出 LowCodeEngine 制作一个动态表格页的通用配方步骤用户操作Schema 层效果运行时机制拖入组件面板拖拽生成组件节点树渲染器按树构建视图配置组件设置器修改属性含 Array 增删排序静态props直接消费绑定数据输入this.state.companiesJSExpression属性parseExpression求值this为渲染器实例动态请求源码面板写componentDidMountlifeCyclesstateoriginCode渲染器生命周期转发执行配置插槽Loading 绑定 拖入插槽插槽容器下的子节点插槽渲染列挂钩浮层列行为设为“弹窗”组件级事件关联配置物料内部控制可见性事件回调按钮事件绑定 回调函数__events 代理JSFunction代理函数透传行级参数想继续深入建议按以下顺序阅读仓库内文档与源码源码面板完整功能代码编辑、样式面板、对接规则docs/docs/demoUsage/panels/code.md同一系列的弹窗页面制作案例docs/docs/demoUsage/makeStuff/dialog.md低代码协议规范组件 Schema、lifeCycles、JSExpression/JSFunction的完整定义docs/docs/specs/lowcode-spec.md渲染器生命周期与表达式解析实现packages/renderer-core/src/renderer/base.tsx、packages/renderer-core/src/utils/common.ts大纲树面板本例中用于管理浮层显隐docs/docs/demoUsage/panels/canvas.md。最后说明适用前提本文基于当前仓库版本示例中的全局 APIwindow.Next.*依赖资产包引入 Fusion Next且源码面板目前不支持async await语法编译见 docs/docs/demoUsage/panels/code.md 的注意事项原文档末尾提到的云端示例 Schema 地址属于外部站点本文不展开可在编辑器左下角 Schema 面板导入任意符合本协议的 Schema 后自行对照研究上述七步的产物结构。【免费下载链接】lowcode-engineAn enterprise-class low-code technology stack with scale-out design / 一套面向扩展设计的企业级低代码技术体系项目地址: https://gitcode.com/GitHub_Trending/lo/lowcode-engine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表