资讯动态

TinaCMS MDX 多模板对象字段实战:用 `_template` 驱动块级组件数据建模与无损往返

发布时间:2026/9/15 10:45:29 来源:尧图企业网站定制
TinaCMS MDX 多模板对象字段实战用_template驱动块级组件数据建模与无损往返【免费下载链接】tinacmsTinaCMS is the leading open-source headless CMS that supports Markdown and Visual Editing. Your content is stored in your own GitHub repo ❤️项目地址: https://gitcode.com/GitHub_Trending/ti/tinacms在 TinaCMS 的富文本编辑体验中rich-text字段不仅支持 Markdown 排版还允许通过模板templates把结构化的 React 组件直接嵌入文档正文。本文以仓库 mdx-block-object-list-template 测试用例 为切入点深入讲解「对象列表 模板」object list with templates这一数据建模方式如何在块级组件如Action的属性中携带一个由_template字段指定具体形态的对象以及 MDX 的解析parse与序列化stringify如何做到无损往返。读完本文你将掌握在 TinaCMS 中定义多形态嵌套对象字段、书写对应 MDX 语法、并通过源码与测试验证其行为的方法。一、测试夹具全景一个最小而完整的多模板对象用例该测试用例位于 packages/tinacms/mdx/src/next/tests/mdx-block-object-list-template/共包含 5 个文件构成一条完整的「输入 MDX → 字段定义 → AST → 输出 MDX → 测试断言」链路文件作用in.md待解析的 MDX 输入定义两个Action块field.ts对应rich-text字段的 schema声明模板与对象子模板node.jsonparseMDX解析后期望的 AST 快照out.mdserializeMDX序列化后期望的 MDX 快照与in.md完全一致index.test.tsvitest 测试解析匹配 node.json序列化匹配 out.md其中in.md的内容是共 17 行包含两个块级组件与一行普通文本Action action{{ _template: popup, title: Say hello, description: This is a description }} / And another template Action action{{ _template: link, title: Say hello, url: http://example.com }} /可以看到Action组件的action属性是一个JSX 表达式属性{{ ... }}花括号包裹的对象字面量对象内通过_template键声明自身形态第一个是popup携带title与description第二个是link携带title与url。这正是「多模板对象」在 MDX 中的书面表达方式。二、字段 Schema 详解rich-text 模板中的嵌套对象模板要让上面的 MDX 被正确解析必须在rich-text字段上声明对应的 schema。完整定义见 field.tsimport { RichTextField } from tinacms/schema-tools; export const field: RichTextField { name: body, type: rich-text, parser: { type: mdx }, templates: [ { name: Action, label: Action, fields: [ { type: object, name: action, templates: [ { label: Popup, name: popup, fields: [ { type: string, name: title }, { type: string, name: descrption }, ], }, { label: Link, name: link, fields: [ { type: string, name: title }, { type: string, name: url }, ], }, ], }, ], }, ], };逐层拆解这个 schema 的嵌套结构顶层templates声明富文本中可用的块级模板block templates。name: Action与 MDX 中的组件名Action一一对应label: Action用于编辑器中展示。这里parser: { type: mdx }明确告诉 TinaCMS 使用 MDX 解析器而非普通 Markdown。模板的fieldsAction模板拥有一个字段action其类型为object——即「对象字段」。对象的templatesaction字段内部再次声明templates包含popup与link两个子模板每个子模板都有自己的fields。这正是「对象列表 模板」的核心同一个对象字段可以在两种或多种形态之间切换形态由数据中的_template键决定。子模板字段的数据类型string、字段名title、descrption、url与 MDX 对象字面量中的键一一对应。需要留意的是popup 子模板中字段名写的是descrption拼写与 MDX 中的description不一致这属于测试用例本身遗留的拼写细节不影响机制理解——实际项目中应保证 schema 字段名与 MDX 键完全一致数据才能被正确映射。与「纯对象列表字段」的区别在 tests 目录下还有一个对比用例 mdx-block-object-list-field。两者命名相似机制不同object list field对象字段不带templates而是扁平地声明多个fields形态固定object list template本文主题对象字段带templates即多模板对象polymorphic object形态可随_template切换。需要多形态复用如按钮既是弹窗触发器又是外链时选择后者形态固定时选择前者即可。三、解析产物AST 中_template的落点node.json记录了parseMDX的期望输出。核心结构如下节选第一个Action{ type: mdxJsxFlowElement, name: Action, children: [{ type: text, text: }], props: { action: { _template: popup, title: Say hello, description: This is a description } } }解读这份 ASTAction被解析为mdxJsxFlowElement节点name保留组件名ActionJSX 属性被收集进props对象action的值就是 MDX 中{{ ... }}内的对象字面量_template原样保留在props.action内部与title、description平级不单独抽离。后续的编辑会话正是靠读取这个键来实例化对应的子模板表单组件若有子内容会被递归处理后放入props.children本用例无子内容因此children仅含一个空文本节点。第二个Action_template: link的 AST 结构完全相同只是props.action变为{ _template: link, title: Say hello, url: http://example.com }。两节点之间的普通文本And another template则被解析为独立的p段落节点——说明模板块与 Markdown 文本可以在同一文档中自由混排。四、底层实现JSX 属性如何变成props对象解析管线由 parse/index.ts 的parseMDX入口驱动先fromMarkdown产出 mdast 树再用compact合并相邻同类型节点最后交给postProcessor。其中关键的一步位于 parse/post-processing.ts 的addPropsToMdxFlownode.attributes.forEach((attribute) { if (attribute.type mdxJsxAttribute) { props[attribute.name] attribute.value; } else { throw new Error(HANDLE mdxJsxExpressionAttribute); } });这段代码遍历 JSX 节点的attributes把mdxJsxAttribute类型的属性按「属性名 → 值」收进props。action{{ ... }}这类表达式属性经 mdast-util-mdx-jsx 解析后其值已经是求值后的对象字面量因此props.action直接就是{ _template, title, ... }这样的普通对象_template键无需特殊处理即自然落入其中。处理完成后node.attributes被删除、node.props被挂载children被替换为空文本节点最终交给remarkToSlate转成 TinaCMS 编辑器使用的数据结构。五、无损往返parse → stringify 的闭环验证「多模板对象」机制能够安全落地离不开解析与序列化的对称性。序列化入口在 stringify/index.ts 的stringifyMDX经过preProcess预处理、normalizeMarkWhitespace规整空白后由toTinaMarkdown依据同一份fieldschema 重新生成 MDX。因为 schema 与输入一致props.action里的_template会在输出时被原样写回{{ _template: ... }}对象字面量。测试用例 index.test.ts 正是验证这一闭环it(matches input, () { const tree parseMDX(input, field, (v) v); expect(util.print(tree)).toMatchFile(util.nodePath(__dirname)); const string serializeMDX(tree, field, (v) v); expect(string).toMatchFile(util.mdPath(__dirname)); });测试断言了两件事parseMDX的输出与 node.json 快照一致其中util.print通过removePosition剔除position定位信息保证快照不随行列号抖动见 tests/util.tsserializeMDX的输出与 out.md 快照一致而 out.md 与 in.md 逐字相同。也就是说同一份 MDX 经「解析 → 序列化」往返后内容不变_template: popup与_template: link两种形态都能被稳定地还原这是多模板对象字段可用于生产内容编辑的前提。六、在自己的 TinaCMS 项目中落地参考本用例在 TinaCMS 项目中配置「对象列表 模板」字段的步骤为在rich-text字段如body的templates中声明块级模板如Actionname与页面组件名保持一致在模板fields中加入type: object的字段如action在其内部声明多个子模板popup、link并为每个子模板配置独立的fields在内容 MDX 中按Action action{{ _template: popup, ... }} /的语法书写对象键与子模板字段名对齐运行parseMDX/serializeMDX见 parse/index.ts 与 stringify/index.ts或直接参考本用例的 index.test.ts 建立快照测试验证往返一致性。其余可交叉验证的用例还包括 mdx-basic-nested-objects、mdx-block-object-list-field 与 mdx-block-scalar-fields分别覆盖嵌套对象、固定形态对象字段与标量属性等相邻场景可作为进阶阅读材料。小结通过 mdx-block-object-list-template 这一个最小用例我们完整走通了 TinaCMS「多模板对象」机制的三个层面schema 层object 字段嵌套 templates 声明多形态、语法层MDX 中_template键指定形态、管线层parse 将 JSX 属性归入props、stringify 原样还原测试保证无损往返。掌握这套模式你就能在富文本正文中安全地嵌入结构可变、可编辑的复杂组件让内容建模既有 Markdown 的自由度又有组件数据的严谨性。【免费下载链接】tinacmsTinaCMS is the leading open-source headless CMS that supports Markdown and Visual Editing. Your content is stored in your own GitHub repo ❤️项目地址: https://gitcode.com/GitHub_Trending/ti/tinacms创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价