可视化编辑设置 (Astro)

Astro 的可视化编辑路径不使用 useTina();该钩子是 React 特有的。相反,Astro 站点使用 @tinacms/astro,这是一个原生的 Astro 渲染器,加上一个小的 postMessage 桥,仅在编辑器 iframe 内加载。

流程:

  1. tina() 集成的请求范围中间件缓冲每个 HTML 响应,并在编辑模式请求时,将桥接引导和每个 TinaCMS 查询页面消耗的一个 <div data-tina-form> 负载拼接到 <head> 中。
  2. 桥接器(从 /admin/bridge.js 加载)读取这些负载,向父管理窗口发送 open,并在内存数据存储中播种。
  3. 当编辑器输入时,管理端将 updateData 回传给 iframe。桥接器存储它。
  4. 页面中的每个可编辑区域都包装在 <TinaIsland> 中,它发出一个 <… data-tina-island="/tina-island/<name>?<params>"> 标记。在每次存储更新时,桥接器将当前覆盖层 POST 到该端点。
  5. 该端点根据覆盖数据重新渲染匹配的 Astro 组件并返回一个 HTML 片段。桥接器将其替换到实时 DOM 中。

在生产环境中(没有管理父级),中间件不注入任何内容,init() 立即退出——生产 HTML 与无 TinaCMS 的 Astro 应用字节相同。(例外:使用 <TinaIsland> 的页面携带一行内联引导,因此当页面静态构建时编辑仍然有效。)

您需要一个 SSR 适配器。 每个岛屿的刷新端点 (/tina-island/[name]) 在每次按键时运行。将 adapter 设置在 astro.config.mjs 中为 @astrojs/node@astrojs/vercel@astrojs/netlify@astrojs/cloudflareoutput: 'server' 是最简单的选择;output: 'static' 也可以,只要您将可编辑区域包装在 <TinaIsland /> 中。

安装

如果您的集合使用 MDX 正文,请添加 @astrojs/mdx。如果您是自托管(没有 TinaCloud),请添加 @tinacms/datalayer

集成连接

astro.config.mjs 中添加一次 tina()。这一调用连接中间件(解析 Astro.locals.tinaEdit 并在编辑模式响应中注入桥接线)并将原生 JS 桥接作为静态资产放置在 /admin/bridge.js

tinaAdminDevRedirect() 是一个仅用于开发的 Vite 插件,将 /admin/admin/ 重定向到 /admin/index.html,以便在 astro dev 期间可以从裸 URL 访问管理 SPA。

没有共享的 <head> 连接组件,没有需要传递的 forms 属性,没有手动 init() 调用。集成处理所有这些。

数据加载器 — 用 requestWithMetadata 包装每个查询

每个路由的数据加载器调用生成的 TinaCMS 客户端,并通过 requestWithMetadata() 管道传递结果。这个调用:

  • { query, variables } 哈希化为桥接用于定位表单的稳定形式 ID。
  • 从请求范围存储中读取桥接的覆盖层,并在页面在管理 iframe 内渲染时将 data 替换为未保存的覆盖层。
  • 使用 tinaField() 需要的元数据标记结果以便点击聚焦。
  • 记录中间件将在编辑模式请求中拼接到 <head> 的表单负载。

priority: 'primary' 将表单标记为页面的主要文档,因此编辑器在加载时打开它,而不是停留在布局级别的全局(例如页眉/页脚配置)。它反映了 useTina()experimental___selectFormByFormId。在 SSR 页面上,第一个 requestWithMetadata() 调用自动被视为主要;当您想要覆盖时,请显式传递。

返回的对象具有 { data, query, variables, id }data 是您渲染的内容,哈希化的 id 是桥接用于将覆盖层匹配回表单的内容。

岛屿注册表

一个小型注册表将每个可编辑区域映射到一个获取器、一个组件、一个外部包装器和一个 propsFromData 投影。添加一个新的可编辑区域在这里是一个条目;动态路由会自动拾取它。

每个岛屿的端点 — 一个通用路由

桥接器在每次按键时 POST 到 /tina-island/<name>。一个动态路由,加上 experimental_createIslandRoute(),处理注册表中的每个条目:

这是桥接器需要的唯一文件。助手强制同源 POST 使用 TinaCMS-preview 内容类型,通过 Astro 的容器 API 渲染注册的组件,并将输出包装在注册的包装元素中——匹配页面侧的 <TinaIsland>,以便桥接器可以将其替换。

在页面中使用可编辑区域

将每个可编辑区域包装在 <TinaIsland> 中。wrapper 属性必须与注册表条目的包装器匹配(桥接器替换整个元素)。标记页面的主要区域为 primary,以便管理端在加载时打开该表单。

添加字段级点击编辑

tinaField() 返回一个字符串,用于标识 DOM 元素对应的表单字段。将其标记在您希望在编辑器中可点击的任何元素上:

@tinacms/astro/TinaMarkdown.astro(子路径)导入 TinaMarkdown, 而不是从裸 @tinacms/astro 导入。Astro 的类型检查器通过子路径直接读取 .astro 文件;裸包默认通过 types 条件解析为一个占位符,Astro 不将其识别为可渲染组件。

粗粒度标记(整个 body)通常是正确的;点击内部的任何富文本节点都会将编辑器聚焦到该字段。请参阅 点击编辑 API 以获取完整的助手参考。

自定义 MDX 嵌入

要在富文本正文中渲染自定义组件(例如,YouTubeEmbed),请编写两个文件:一个描述编辑器 UI 的 schema Template,以及一个与模板同名的 Astro 渲染器。

1. schema Template:

2. Astro 渲染器:

在富文本字段的 templates 数组中注册模板:

并在 <TinaMarkdown components={…}> 映射中注册渲染器:

两个 name 字符串必须匹配。 模板的 name: 'YouTubeEmbed' 和组件映射键 YouTubeEmbed 是渲染器从富文本 AST 中调度 mdxJsxFlowElement 节点的方式。不匹配会将嵌入渲染为可见的占位符,以便您在开发期间发现缺失的注册。

默认标签覆盖

同一个 components 映射可以覆盖任何富文本节点的默认 HTML 标签,方便在不分叉渲染器的情况下进行样式设置:

支持的覆盖键:ph1h6ulolliblockquotelicaimgcode_blockhrbreak。请参阅 @tinacms/astro README 以获取完整的节点参考。

CMS 提供的 aimg 节点中的 URL 通过 sanitizeHref / sanitizeImageSrc,阻止 javascript:data:vbscript: 和协议相对 URL。两个助手都在 @tinacms/astro/sanitize 上公开,以便在您自己的组件中使用。

静态站点编辑

支持 output: 'static'。上述中间件仅在按需渲染的路由上运行,因此在预渲染页面上它从不注入任何内容——相反,<TinaIsland> 发出一个小的内嵌引导脚本,仅在页面在管理 iframe 内打开时加载 /admin/bridge.js。在启动时,桥接器获取每个岛屿的 /tina-island/[name] 端点(仍然是 prerender = false,因此适配器按需渲染它)以获取页面的表单负载,然后编辑工作与在 SSR 项目中完全相同。

静态编辑的要求:

  • 将每个可编辑区域包装在具有注册岛屿的 <TinaIsland> 中——这既是桥接器重新渲染区域的方式,也是引导程序进入页面的方式。
  • 在页面的主要 <TinaIsland> 上传递 primary。在静态页面上,桥接器无法自动判断哪个岛屿是“页面”,因此没有这个,编辑器可能会停留在多文档选择器上。
  • 保持 export const prerender = falsesrc/pages/tina-island/[name].ts 上。

权衡:使用 <TinaIsland> 的页面在生产 HTML 中携带那一行内联引导——它不再与无 TinaCMS 的 Astro 应用字节相同。没有 <TinaIsland> 的页面保持不变。

跨域管理

如果您的管理在不同的域(Codespaces、独立域自托管),请在您的 .env 中设置:

用逗号分隔以允许多个(预览 + 生产)。中间件内嵌它,以便桥接器验证入站 postMessages。

子包导出

您需要的一切都在 @tinacms/astro 下:

子路径

提供的内容

@tinacms/astro

requestWithMetadatatinaFieldQueryResult 和富文本类型

@tinacms/astro/TinaMarkdown.astro

<TinaMarkdown content components /> — 富文本渲染器。请从此子路径导入,以便 Astro 的检查看到一个真实的 .astro 组件。

@tinacms/astro/TinaIsland.astro

<TinaIsland name wrapper params [primary] /> — 可编辑区域的标记包装器

@tinacms/astro/integration

tina() 集成 — 自动连接中间件并放置 /admin/bridge.js

@tinacms/astro/middleware

集成自动连接的中间件 — 导出以防您需要手动组合

@tinacms/astro/data

requestWithMetadataQueryResult

@tinacms/astro/tina-field

tinaField() 助手用于 data-tina-field 标记

@tinacms/astro/experimental

experimental_createIslandRoute()IslandRegistryIslandConfig

@tinacms/astro/is-edit-mode

isEditMode(request) — 服务器端管理 iframe 检测

@tinacms/astro/types

TinaRichTextContentCustomComponentsMapTinaRichTextNodeMdxElementTextElement

@tinacms/astro/sanitize

sanitizeHref / sanitizeImageSrc 用于 CMS 提供的 URL

@tinacms/astro/bridge

initrefreshForms@tinacms/bridge 的其余部分

@tinacms/astro/vite

tinaAdminDevRedirect() — 仅用于开发的重定向,从 /admin/admin/index.html

另请参阅

Last Edited: May 26, 2026