amis 配置与组件:从 JSON Schema 到组件树的低代码页面构建指南
2026/9/13 23:26:51 网站建设 项目流程

amis 配置与组件:从 JSON Schema 到组件树的低代码页面构建指南

【免费下载链接】amis前端低代码框架,通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis

本篇技术指南以 amis(前端低代码框架)的核心概念「配置与组件」为主题,系统讲解如何通过一段 JSON 配置驱动页面渲染:从最简的type+body结构出发,逐步深入到组件节点的通用构成、容器组件与组件树的嵌套规则,再到一个完整的树形布局实战示例,最后结合amis-core源码剖析「JSON → React 组件」的底层渲染链路。读完本文,你将掌握 amis 页面配置的最小骨架、组件树的组织规律,以及如何在复杂页面中通过嵌套组合实现布局。

配置是 amis 的核心思想

amis 是一款「通过 JSON 配置就能生成各种页面」的前端低代码框架。与传统的命令式编程不同,使用 amis 时你不需要编写一行 HTML/JSX,而是编写一份描述性的 JSON Schema:它声明了「页面上有哪些组件、组件长什么样、组件之间如何嵌套、数据从哪来」。框架在运行时读取这份配置,将其解析为一棵组件树并递归渲染成真实页面。

在 amis 的官方文档体系中,这个概念文档位于 docs/zh-CN/concepts/schema.md,是理解所有 amis 用法(表单、CRUD、布局、事件联动等)的基石。下面我们沿着官方文档的脉络,从最简单的配置开始讲起。

最简单的 amis 配置

一个最简单的 amis 配置看起来是这样的:

{ "type": "page", "body": "Hello World!" }

请观察上面的代码,这是一段 JSON,它的含义是:

  1. type是 amis 节点中最重要的字段,它告诉 amis 当前节点需要渲染的是Page组件。
  2. body字段会作为Page组件的属性,Page组件根据这个值来渲染页面内容。

这段配置的效果是页面上渲染出一段文本「Hello World!」。它本质上完成了两件事:指定渲染哪个组件type),向该组件传递属性body等其余字段)。

实时预览与修改

在 amis 官方文档站的示例区域(即原文档中```schema代码块所在的位置),上述配置是可以实时修改预览的,你可以尝试修改一下Hello World!的值,页面会即时刷新。

不过这个实时预览功能对于某些属性不生效,如果发现不符合预期,需要复制 JSON,打开另一个页面后粘贴。

也就是说,实时预览覆盖了大多数常规属性的修改,但个别属性(例如某些初始化类、需要重新挂载才生效的配置)不会即时响应,此时重新粘贴 JSON 打开即可。这一限制在 amis 编辑器(amis-editor)中同样存在,设计复杂页面时建议以「重新渲染」后的结果为准。

组件:type 字段与属性的组合

上面提到,type字段会告诉 amis 当前节点渲染的组件为Page组件节点的配置永远都是由type字段(用于标识当前是哪个组件)和属性构成的

{ "type": "xxx", ...其它属性 }

这是一条适用于 amis 所有节点的通用规则:

  • type:节点的「身份标识」,必须是字符串,且与已注册渲染器的类型一一对应。比如pagetplformcrudchartgrid等。
  • 其余字段:全部作为该组件的属性(props)传入。不同组件有各自不同的属性集合,例如Pagebodytoolbartitle等,表单组件有namelabel等。

从类型定义看,节点的 schema 在 packages/amis-core/src/types.ts 中被声明为Schema接口,它的本质是一个「开放对象」——除了极少数约定字段外,任意属性都可以存在,具体含义由对应渲染器解释:

export interface Schema extends AMISSchemaBase { children?: JSX.Element | ((props: any, schema?: any) => JSX.Element) | null; component?: React.ElementType & { wrapedAsFormItem?: any; }; [propName: string]: any; }

[propName: string]: any意味着 schema 是一个高度灵活的结构,这正是「配置即组件属性」这一设计得以成立的基础。

组件树:对象嵌套与数组并列

单个组件无法构成复杂页面。这次我们看一个稍微复杂一点的配置:

{ "type": "page", "body": { "type": "tpl", "tpl": "Hello World!" } }

该配置渲染的最终效果和前面的示例一样,但这次Page组件的body属性值配置了一个对象通过type指明body内容区内会渲染一个叫Tpl的组件,它是一个模板渲染组件(用于渲染带变量插值的文本模板)。

body 中使用数组并列多个组件

body中除了配置对象,还可以是数组,比如下面的例子:

[ { "type": "tpl", "tpl": "Hello World!" }, { "type": "divider" }, { "type": "form", "body": [ { "type": "input-text", "name": "name", "label": "姓名" } ] } ]

可以看到通过数组的形式,增加了divider(分割线)和form(表单)组件。数组中的每个元素都是独立的 schema 节点,amis 会按顺序依次渲染它们,form内部又通过自己的body数组嵌套了input-text(文本输入框)表单项。

这种「对象 + 数组」的自由组合,构成了 amis 组件树的全部结构语法:对象表示「唯一子节点」,数组表示「多个并列子节点」。在 packages/amis-core/src/types.ts 中,这个规则被抽象为SchemaNode类型:

export type SchemaNode = Schema | string | Array<Schema | string>;

即一个节点要么是完整的 schema 对象,要么是字符串(作为纯文本/模板),要么是二者的数组——string会作为纯文本内容渲染,数组则按序渲染每个子节点。

容器型组件:树形结构的承重墙

除了Page之外,还有很多容器型的组件都有body属性,例如paneldialogdrawertabsgridform等。容器组件负责「承载」子节点,子节点既可以是对象也可以是数组,通过这种一层套一层的树形结构,amis 就能实现复杂页面制作。

注意:

Page是 amis 页面配置中必须也是唯一的顶级节点

也就是说,一份完整的 amis 页面配置,最外层一定是一个type: "page"的对象,所有其他组件都必须以 Page 的子节点(或孙子节点)形式出现。这一约束在 packages/amis/src/renderers/Page.tsx 的渲染器注册处也有体现——page渲染器被声明为isolateScope: true(隔离作用域),即每个页面形成独立的数据与渲染边界:

@Renderer({ type: 'page', storeType: ServiceStore.name, isolateScope: true }) export class PageRenderer extends PageRendererBase {}

实战:通过树形来实现布局

下面这个页面就是通过树形组合出来的,大体结构是这样:

Page ├── Toolbar │ └─ Form 顶部表单项 ├── Grid // 用于水平布局 │ ├─ Panel │ │ └─ Tabs │ │ └─ Chart │ └─ Panel │ └─ Chart └── CRUD

对应的完整配置如下(这是 amis 官方文档提供的一个典型「数据看板」式页面,综合了顶部筛选表单、图表面板与列表 CRUD):

{ "type": "page", "toolbar": [{ "type": "form", "panelClassName": "mb-0", "title": "", "body": [{ "type": "select", "label": "区域", "name": "businessLineId", "selectFirst": true, "mode": "inline", "options": ["北京", "上海"], "checkAll": false }, { "label": "时间范围", "type": "input-date-range", "name": "dateRange", "inline": true, "value": "-1month,+0month", "inputFormat": "YYYY-MM-DD", "format": "YYYY-MM-DD", "closeOnSelect": true, "clearable": false }], "actions": [], "mode": "inline", "target": "mainPage", "submitOnChange": true, "submitOnInit": true }], "body": [{ "type": "grid", "columns": [ { "type": "panel", "className": "h-full", "body": { "type": "tabs", "tabs": [{ "title": "消费趋势", "tab": [{ "type": "chart", "config": { "title": { "text": "消费趋势" }, "tooltip": {}, "xAxis": { "type": "category", "boundaryGap": false, "data": ["一月", "二月", "三月", "四月", "五月", "六月"] }, "yAxis": {}, "series": [{ "name": "销量", "type": "line", "areaStyle": { "color": { "type": "linear", "x": 0, "y": 0, "x2": 0, "y2": 1, "colorStops": [{ "offset": 0, "color": "rgba(84, 112, 197, 1)" }, { "offset": 1, "color": "rgba(84, 112, 197, 0)" }], "global": false } }, "data": [5, 20, 36, 10, 10, 20] }] } }] }, { "title": "账户余额", "tab": "0" }] } }, { "type": "panel", "className": "h-full", "body": [{ "type": "chart", "config": { "title": { "text": "使用资源占比" }, "series": [{ "type": "pie", "data": [{ "name": "BOS", "value": 70 }, { "name": "CDN", "value": 68 }, { "name": "BCC", "value": 48 }, { "name": "DCC", "value": 40 }, { "name": "RDS", "value": 32 }] }] } }] }] }, { "type": "crud", "className": "m-t-sm", "api": "/api/mock2/sample", "columns": [{ "name": "id", "label": "ID" }, { "name": "engine", "label": "Rendering engine" }, { "name": "browser", "label": "Browser" }, { "name": "platform", "label": "Platform(s)" }, { "name": "version", "label": "Engine version" }, { "name": "grade", "label": "CSS grade" }] }] }

这个示例里用到的关键组件值得逐个拆解:

组件type 值作用
页面容器page整个页面的顶级节点,承载toolbarbody
顶部表单form筛选条件区,mode: "inline"使其横向排列,submitOnChange让条件变化即触发提交
下拉选择select区域筛选,「北京/上海」两个静态选项
日期范围input-date-range时间筛选,value: "-1month,+0month"表示默认近一个月
水平布局grid通过columns数组把页面分成左右两栏
面板panel带边框与标题的内容容器,className: "h-full"让两栏等高
标签页tabs内部再嵌套多个tab,每个 tab 渲染一个图表
图表chart直接内嵌 ECharts 的config配置(折线图、饼图)
列表crud通过api拉取数据并以表格展示,columns声明列

细心的读者会发现,grid的列里放的是panelpanelbody里放的是tabstabs的 tab 里放的是chart——每一层都是「容器组件的属性(columns/body/tabs/tab)接收子节点配置」,层层递进直到叶子组件。这正是 amis 组合式布局的精髓。

官方文档同时指出:amis 后续将会实现新的布局模式,将更容易实现复杂布局效果。届时树形嵌套的书写成本有望进一步降低,但组件树与容器嵌套的底层模型不会改变。

底层原理:从 JSON 到 React 组件的渲染链路

理解了「怎么写配置」之后,我们来看看 amis 是如何把这段 JSON「翻译」成真实页面的。这有助于你在排查配置不生效、或遇到「找不到渲染器」类报错时快速定位问题。

第一步:渲染器注册表

每个type值对应一个渲染器(Renderer)。渲染器通过registerRenderer注册到全局注册表中,核心实现在 packages/amis-core/src/factory.tsx。其注册配置RendererBasicConfig(同文件 L47-L76)中几个关键字段:

  • type:节点type字段匹配用的类型名,注册时会自动转小写,并基于它生成正则test规则;
  • test:自定义匹配规则(正则或函数),用于根据 schema 判断是否命中该渲染器;
  • alias:别名数组,多个 type 可命中同一个渲染器;
  • weight:匹配权重,值越低越优先命中;
  • storeType:绑定的状态仓库类型(例如 Page 绑定ServiceStore);
  • override:设为true时可覆盖已注册的同名渲染器。

页面组件、模板组件、CRUD 组件的注册都遵循这一机制,例如 Tpl.tsx 中@Renderer({type: 'tpl', ...})装饰器本质就是调用registerRenderer;CRUD.tsx 同样以@Renderer({...})声明。tpl渲染器支持tpl/html/text/raw多种取值,其中raw原样输出、tpl走变量插值管道(filter),这就是文档示例中"tpl": "Hello World!"能被渲染成文本的原因。

第二步:SchemaRenderer 递归解析

运行时,amis 通过 SchemaRenderer 这个核心类处理每个 schema 节点:

  1. resolveRenderer()(L248-L301)根据节点的type从注册表中解析出对应渲染器组件;
  2. render()(L398 起)处理数组节点(Array.isArray(schema)时交给render递归)、计算visible/hidden/disabled等表达式属性,然后渲染组件;
  3. renderChild()(L355-L391)负责把容器组件的子节点(bodycolumnstoolbar等区域)继续向下传递渲染,从而形成深度优先的递归渲染——子节点的渲染结果逐层返回,最终拼出整棵组件树对应的 DOM。

这也是为什么「容器属性(如body)里填对象或数组都能生效」:renderChildSchemaNode统一处理,无论传进来的是单个对象还是数组,都会继续走同一套解析流程。

第三步:找不到渲染器怎么办

如果某个节点的type在注册表中不存在,resolveRenderer解析不到对应组件,factory.tsx 中的loadRendererError会返回一个运行时错误提示,其中会展示出错的路径与原始 schema:

export function loadRendererError(schema: Schema, path: string) { return ( <div className="RuntimeError"> <p>Error: 找不到对应的渲染器</p> <p>Path: {path}</p> <pre> <code>{JSON.stringify(schema, null, 2)}</code> </pre> </div> ); }

排查配置问题(例如拼错了type值、或使用了未注册的自定义组件)时,这个错误信息里的Path就是定位问题的第一线索——它会精确指出是组件树中哪一级节点匹配失败。

总结与进阶路径

回到开篇的问题:amis 的页面本质上就是一棵由 JSON 描述的组件树。掌握它只需抓住三条规则:

  1. 一个节点 =type标识 + 一组属性type决定渲染哪个组件,属性决定组件行为;
  2. 容器组件的属性(bodycolumnstoolbar等)接收子节点,子节点可以是对象(唯一子节点)或数组(并列子节点),层层嵌套形成树;
  3. Page是唯一且必须的顶级节点,一切内容都在它的子树中。

在底层,SchemaRenderer 配合 factory.tsx 的渲染器注册表,把这份 JSON 递归解析成 React 组件并渲染到页面。

如果你希望继续深入,可以沿着以下路径扩展学习:

  • 掌握常用组件属性与表单配置,见 表单相关文档、文本/模板组件 Tpl、CRUD 列表;
  • 了解布局类容器的具体用法,见 Grid 栅格、Panel 面板、Tabs 标签页、Chart 图表;
  • 深入理解数据流与表达式,见 数据映射、表达式、模板;
  • 阅读 amis-core 源码中 SchemaRenderer.tsx 与 factory.tsx 的完整实现,理解渲染器注册与解析的每一个细节。

【免费下载链接】amis前端低代码框架,通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询