# @compmd/render 中文文档

规范地址：https://npmcn.com/package/%40compmd/render/

版本：0\.6\.0
npm 元数据更新时间：2026-11-09T15:23:00.328Z
中文译文更新时间：2026-11-10T13:58:03.822Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40compmd/render
原文对照：https://npmcn.com/package/%40compmd/render/?lang=original
项目主页：https://compmd.hakanserce.com/
源码仓库：https://github.com/comp-markdown/compmd

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：245 kB，57 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：react ^19，svelte ^5，react-dom ^19
- 首次发布：2026-10-30T09:11:30.769Z
- 最新版本发布：2026-11-09T15:22:59.954Z
- 近 30 天下载量：2337（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：10（近 12 个月 10 个）

## 中文简介

Renders a CompMD 扩展树作为活页:Markdown,布局,输入和主机语言组件通过主机合同.

## 安装

```sh
npm install @compmd/render
```

也可以使用：`pnpm add @compmd/render`、`yarn add @compmd/render`、`bun add @compmd/render`

## README

![CompMD](https://raw.githubusercontent.com/comp-markdown/compmd/main/logo/compmd-light.svg)

# @ compmd/ 移交

制作一个 CompMD 扩展树([第12.3节](https://npmcn.com/package/%40compmd/compmd-spec-v1.md#123-the-expanded-tree))作为活页:通过主机合同(§7.4)的Markdown,布局,输入和主机语言组件,并带有React,Svelte 5和plain绑定(§7.6). 新树更新了已有的页面,因此组件保持其实例和状态.

**网站:** [(原始内容存档于2018-10-21). compd.hakanserce.com](https://compmd.hakanserce.com/)并有一个游乐场来尝试CompMD.

它使树; 它不处理文档。 处理器(阶段1至4b, spec §11)给它树: [`@compmd/processor`](https://www.npmjs.com/package/@compmd/processor) 在浏览器中.

```sh
npm install @compmd/render @compmd/processor
```

它执行草案 [CompMD 规格](https://compmd.hakanserce.com/spec/), 第1版 (中文(简体) ). 其版本为 `0.x` 在spec's版本1发布之前,它与 `@compmd/processor` (单位:千美元)[如何释放工作](https://github.com/comp-markdown/compmd/blob/main/docs/releases.md)) (中文(简体) ).

**版本数 :**

-   **0.6.0 (中文(简体) )** a React 或 Svelte 组件在抛出或失败后的下个更改时再次绘图.
-   **0.5.0: (中文(简体) )** 在页面上每行文字的位置(`page.lines()` 财务报告和审定财务报表 `region.lines()`,每行箱的发电机,以及 `onLayout`当他们移动时,为一排行号; `context.busy(work)` 用于仍然绘制的组件(React和Svelte绑定物中第7.4段),以及 `page.drawn()`等待着它。 中断:框架协议是版本4(`lines`, (中文(简体) ), `layout`, (中文(简体) ), `drawn`),所以一页和一帧0.4.0互相拒绝.
-   **0.4.0: (中文(简体) )** spec's 草案截至2026-11-03 (中文(简体) )[其更改日志](https://github.com/comp-markdown/compmd/blob/main/CHANGELOG.md): 页面来自何处, 两者兼有(`sourceOf`, (中文(简体) ), `elementsAt`, (中文(简体) ), `reveal`,并通过一个框架 `reveal`, (中文(简体) ), `rectsAt` 财务报告和审定财务报表 `point`(三); `highlight`,对于显示为代码的代码块;一个待处理的包的用法绘制为加载(`componentPending`); 其它文档的图像 (`images`, (中文(简体) ), `imageSources`每个失败者都命名其用途,以及 `onRecovered` 当它再次画出时; 组件在它们的盒子被放置和样式后被挂起。 打破:帧协议为第三版,因此一页和一帧为0.3.0相拒,并 `Footnotes.definitions` 给出每个定义的节点.
-   **0.3.0: (中文(简体) )** 与0.2.2相同的渲染器 `@compmd/sandbox`观察者,用于开发工具,以及第一个版本 `@compmd/devtools`,该开发者工具作为任何页面嵌入的一部分.
-   **0.2.2: (中文(简体) )** 与0.2.1相同;第一个版本的发布工作流程阶段和作者批准;第一个版本的软件包工作流程先由手取出,0.2.0,这证明了其值得信赖的出版.
-   **6.2.1:** `@compmd/sandbox` 缩放一个框架,浏览器不会对它的内容进行渲染(低于折叠,或太小,无法看到),一个框架可能在0.2.0中漏放;其他包在0.2.0中一样. 印发日期 `@compmd/render` 财务报告和审定财务报表 `@compmd/processor` 仅: 发布停止在沙盒, 其信任的出版商允许单独进行.
-   **0.2.0: (中文(简体) )** spec's 草案截至2026-11-02 (中文(简体) )[其更改日志](https://github.com/comp-markdown/compmd/blob/main/CHANGELOG.md):在修改中,代码渲染器(一个由组件绘制的代码块,其代码块为倒置),以及主机合同的 `scheme` 财务报告和审定财务报表 `fail`: 组件遵循页面的颜色方案(`page.scheme()`, (中文(简体) ), `schemeOf`),一个失败的组件会显示其倒数至下一次更新。 与第一版一起发行 `@compmd/sandbox`, (中文(简体) ), `@compmd/registry`, (中文(简体) ), `@compmd/vite`, (中文(简体) ), `@compmd/pack` 财务报告和审定财务报表 `@compmd/create-pack`。 。 。 .
-   **6.1.1:** 和0.1.0相同;发布工作流程的第一个版本发布.
-   **0.1.0 : (简体中文)** 第一个版本.

## 图标

```sh
pnpm install         # in the repository root
pnpm test            # unit tests in a DOM (happy-dom)
pnpm lint            # eslint and the type check, svelte-check for the Svelte test component
pnpm build           # ESM and types into dist/
```

## 三层

| 层 | 入境点 | 它意味着什么 |
| --- | --- | --- |
| **页次** | `createPage(root, options)` | 整棵树,逐块地从整棵树或花序上,加上只有整棵树的(容器断点查询,主题符号,脚注编号和结尾的列表,链接定义,输入) |
| **地区** | `createRegion(target, options)` | 任何节点列表,按密钥更新;组件通过组件层 |
| **构成部分** | `mountComponent(target, node, options)` | 其外框中有一个主机语言组件;呼叫者使其槽和回落 |

```ts
import { createPage } from "@compmd/render";
import { react } from "@compmd/render/react";

const page = createPage(document.body, {
  components: { chart: drawChart, card: react(Card) },     // plain components are their own mount
  onSet: (input, value) => processAgain({ [input]: value }),
  tokens: { "--compmd-accent": "#0b7285" },
});

page.render(tree);                                          // an input or data changed: the text didn't
page.render(tree, { text, diagnostics, edit });             // a keystroke in an editor
page.splice([splice], { text, diagnostics });               // a keystroke, with a document kept open
```

**块.** 页面将树的顶级节点作为块来保存,每个节点都会被渲染一次. 更改是它们的一环,因为处理器可以保持文档的开放性`Splice`: 节点 `from..to` 成为 `nodes`之后的节点移动 `lines` 财务报告和审定财务报表 `offset`) (中文(简体) ). `page.splice` 依次取出相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相相接相接相相相接相相接相接相接相相接相相相接相相相接相接相相相相相接相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相; `page.render` 是每个街区的一环。 只有整棵树来自每个块的汇总,所以其他地方的块只有在使用所改变的东西时才会更新:脚注编号,链接定义,输入. 横跨生 HTML 配对的块(`<details>`马克顿, `</details>`) 组合在一起.

**钥匙.** 每个节点都有一个 `origin` (参见第12.3节 `origins` 特性)获得一个密钥: ID / 来源范围,每一次编辑后作为编辑器地图位置,同时有节点发生. 一个节点 它的牧场 在一个老人去的地方 保持它的视野。 剪接器有它的编辑, 在代码点。 对于 `render`, (中文(简体) ), `edit` 是旧文本的行距,编辑器被替换,在 UTF-16 偏移中,作为文本区域的选择或 CodeMirror 交易给出的;没有它,则对文本进行比较。 无出处的节点相匹配的地方.

**无效的文本 .** 由于诊断方法的改变,该页保留了它显示的文本无效的中文本,除了宽大恢复(spec §10.3):

1.  不解析的前题(F001,F033):最后的好页面会保留. 块沿相接而来, 并再次显示它.
2.  一个没有关闭的顶级容器(F004):它的开口器显示为一段落,下面的内容停留在原地.
3.  顶级块中的任何其他出错:该块保留了上个好渲染,其余的更新.

**断点** 属于容器查询:每个块的参数跟随其周围的盒子的宽度(Spec §9.3),所以当块被放入其中时,一个框就是容器,页面总是. 页面取出其调用者所放位置的宽度,因此弹性行中的页面根需要宽度,否则会缩到一无所有.

**当一个组件上架时.** 页面或区域会挂载在文档中框并写出其样式的渲染件,所以 `mount` 获得一个框,其中包含其常见的参数、页面的主题符号和位置,按文档顺序排列: 在其槽中的人前面的组件,在它挂起时将其放在自己的DOM中. `mountComponent` 即刻被直接调用,进入呼叫者给予的目标 `later` 选项会延后调用器的挂载,然后将框放入.

**区域** 沿最近的容器行走,由呼叫者提供:在一页、一页或一框内;在其他地方,区域的目标或周围有类的元素 `compmd-container` (或 `container-type: inline-size`) (中文(简体) ). 区块使用没有集装箱的断点的区域报告 `no-container` 一次通过 `onError`,当其目标位于文档中。 区域并列给每个面板自己的容器,因此每个面板都遵循自己的宽度:

```ts
for (const [pane, nodes] of [[left, before], [right, after]]) {
  pane.classList.add("compmd-container");
  createRegion(pane, { components, stylesheet }).render(nodes);
}
```

**代码块和数学.** `code: { mermaid: (source, target) => … }` 制作一种语言的栅栏编码 `math: (tex, { display }, target) => …` 使数学。 没有它们,代码显示为代码块,而数学显示为它的TeX源,如spec §2.3所言. 代码屏蔽文档的代码渲染器( spec §7. 7; 树给它) `component` 财务报告和审定财务报表 `alt`从 `components` 在其框中,作为一叶:块的文字是它的 `code` 原子弹, `alt` 联合国 `fallback.text`,代码阻止它的倒置。 它代替了 `code` 因为它的语言,因为文档的导入胜过主机.

**突出显示.** 代码块显示为代码, `<pre><code class="language-…">`,是当部件缺失或失效时,一个没有渲染器绘图,或者代码渲染器倒置. `highlight: (code, language, target) => …` 强调: `target` 是块的 `<code>`(一) 持有其文本,亮点器用其标志来取而代之,即时或一并装入其需要的; `language` 是栅栏的,或 `""`。只有当块的文本或语言发生变化时才再次使用。 没有它,文本是明确的. [`@compmd/sandbox`](https://npmcn.com/package/%40compmd/sandbox/README.md#code-blocks) 默认给一个,Shiki's`shikiHighlight()`),该页随页 `createPage` 也能够承受.

**其他地方的图像.** 一个无法装入图像本身的页面, 如一个没有网络的框架, 给出 `images: (src) => …`,它用 URL 决定显示图像 `src` 联合国 `blob:` 其主机已获取的文件的 URL, 或 `undefined` 当它不能拥有。 标记下图像,通过参考图像和原始 HTML 图像,然后显示其备选文本,在 `<span class="compmd-image-alt">`直到它解决, 当它不能。 没有它,一个形象是 `<img>` 从它的装入 `src`。 。 。 . `imageSources(nodes)` 列出 `src` 对于只获取这些图像的主机来说.

**光阴相克.** 一个组件的 `context.scheme` 是页面或区域构成的颜色图案: `color-scheme`,以及读者的偏好,如果它允许两者兼而有之(`schemeOf(element)`) (中文(简体) ). 每次渲染、读者偏好改变、印刷开始和结束时都会读取;一个主机,用类调转换自己的主题 `page.scheme()` (或 `region.scheme()`)后为后. 当方案改变时,页面上的每个组件都会得到它和一个 `update` 和同样的段落。 用 CSS 颜色绘图的组件不需要这些; 绘制时取其颜色的组件( 图表, 画布图) 读取 `context.scheme`。 。 。 .

**失败的组件 .** `context.fail(message)` 用于在 `mount` 或者说 `update` 返回时, 它无法绘制它得到的: 它报告 `threw` 结束 `onError` 与 `message` (W118),并显示回落到下一个 `update`,当盒子被取出并归还。 扔进去 `update` 相同; 丢入 `mount` 显示好的倒数。 每个错误都标明其用途, `use`,在窗口中独有的id, 当使用在这样的失败后再次抽取, `onRecovered({component, use})` 说到这个,所以一个列出失败的宿主就取消了它;一个框架将它贴在 `recovered`。 。 。 .

**组件仍在绘制中 .** `context.busy(work)` 用于在 `mount` 或者说 `update` 返回: `work` 是绘制的保证(第7.4段). `page.drawn()` (和 `region.drawn()`一旦最后的成像和相片的部件 和它们给出的每一个承诺 `busy` 已经解决、履行或拒绝,或在 `BUSY_MS` (10 s) 对于一个从未这样做的人; 后期的变形等待自己的变形。 没有什么显示不同 同时。 一个帧的结尾告诉它的宿主相同(`drawn`, (中文(简体) ), _在一个框架_)它是一个沙盒构建它 `settled` 继续.

## 从哪里来的页面

嵌入页面的应用程序往往需要页面显示的内容与制作该页面的文本之间的链接. 编辑器将其注意点移动到读者点击的地方,或者将预览滚动到注意点;一个评论工具标记评论上的段落. 页面和一个区域保存它,从树的起源(第12.3节:请用 `origins: true`),并给予两者:

| 打电话 | 给 |
| --- | --- |
| `page.sourceOf(node)` | 文本范围 `node`,页面的元素或文本节点(在组件的阴影根中也有一个),或 `undefined` |
| `page.elementsAt(offset)` | 要点: `offset` 绘图,或 `[]` |
| `reveal(elements)` | 卷到他们身上, 少如显示第一, 和标记每个为 `REVEALED_MS` (1.5 s) (中文(简体) ) |

```ts
import { codePointOffset, createPage, reveal, utf16Offset } from "@compmd/render";

const page = createPage(preview, { components });
page.render(tree, { text });                               // a tree processed with `origins: true`

// The reader clicked in the preview: the caret goes where it came from.
preview.addEventListener("click", (event) => {
  const source = page.sourceOf(event.target as Node);
  if (source?.start.offset === undefined) return;
  const caret = utf16Offset(text, source.start.offset);
  textarea.setSelectionRange(caret, caret);
});

// The caret moved: the preview shows what it is in.
textarea.addEventListener("selectionchange", () => reveal(page.elementsAt(codePointOffset(text, textarea.selectionStart))));
```

**范围** (单位:千美元)`Source`)为 `{start, end}`,每个点作为来源有: `line` 财务报告和审定财务报表 `column` 基于1, `offset` 以0为基数,列并相抵编码分数(spec §10.5). 在目前的案文中: `page.splice`,它所保存的块的由来在文本后面,根据它们之前的变化,页面移动它们. 编辑器的偏移是UTF-16(一个文本区域的选择,CodeMirror的位置): `codePointOffset(text, utf16)` 财务报告和审定财务报表 `utf16Offset(text, codePoint)` 改变他们.

**什么地图是什么.** 页面DOM地图的每个节点到它所绘制的被扩展的节点,或者,当它没有自己的节点时,到它周围最近的有一个节点. 因此,起源规则(spec §12.3)决定点击给出的:

| 点击什么 | 范围 |
| --- | --- |
| 标记 | 其自有节点的: `*em*` 给予强调, 连接它的联系 |
| 案文a `value` 或生成的插值 | 节点持有它,它的家长 |
| 这算什么 `compmd` 定义的正文 | \* 本文件的任何深度引用 |
| 主机语言组件自己的 DOM | 组件; 其槽项, 每个块 |
| 末尾列表中的脚注项目 | 它的定义 |
| 渲染器添加的内容( 任务复选框、 脚注的QQ、 提醒的标题) | 属于它的节点 |
| 一个组件的回落,而它显示 | 它自己的节点' |

**区域绘制的元素 .** `elementsAt` 取最内侧的偏移范围,从它的开始到它的结束;当一个范围结束到下一个开始时,从那里开始,在最后一个区域结束时,那一个。 范围可以绘制若干要素: `each` 和每个模板插槽的示例(它们共享模板的范围),所有它们。 在一个要素范围内,一个范围是相互之间 `compmd` 组件的盒子及其身体,最外侧.

**其所限.** 没有起源的一棵树什么也没有地图 在文本无效时保留其最后良好渲染的块(上方规则3)将其全部映射到当前文本中的块范围,因为它显示的是一个更古老的文本;虽然前题不解析(规则1),但页上仍然显示的块却让地图一无所获. 在一个组件自己的DOM内部,没有什么比组件更精细了,一个组件在它自己的框架(沙盒的用框)中给组件整体绘制出什么. 一个区域地图来自它最后制成的节点的由来,如给出的:它没有分枝.

**`reveal`标记** 是类 `compmd-revealed`,主题口音中的纲要(`--compmd-accent`)),主机可能重新样式. 一个元素的第二次揭示再次开始.

## 每行在何处

查看器在页面旁边的小沟中显示文本的行号,或者标出注释上的行号,需要页面显示的文本中的每一行. 页面和某个区域给出的 来源与盒子相同, 当他们移动:

| 打电话 | 给 |
| --- | --- |
| `page.lines(from?)` | a 发生数 `{line, rects}`,当前文本的每行都有一个,按照行顺序从行中绘制一些东西 `from` (没有它): `rects` 它的文本显示在框中, `{x, y, width, height}`在页根左上角的 CSS像素中 每道线都是在发电机到达时测量的 所以一条沟在显示测量的底部停止 |
| `onLayout()`,选择 `createPage` 财务报告和审定财务报表 `createRegion` | 当页面显示移动时调用, 最多一次是一个动画框架 |

```ts
import { createPage } from "@compmd/render";

const page = createPage(preview, { components, onLayout: drawGutter });
page.render(tree, { text });                    // a tree processed with `origins: true`

/** The numbers of the lines that show, beside them: the gutter scrolls with the page. */
function drawGutter() {
  const numbers = [];
  for (const { line, rects: [first] } of page.lines(firstLineShown)) {
    if (first.y > preview.scrollTop + preview.clientHeight) break;   // past what shows: the rest isn't measured
    numbers.push(number(line, first.y));
  }
  gutter.replaceChildren(...numbers);
}
```

**一条线的位置** 从规则中抽出的内容表明,从规则的第一个性质到最后一个性质:

| 线条是什么 | 它的直径 |
| --- | --- |
| 文字 在一款,标题,列表项,引文,表行,脚注的定义 | 其文字的框,每个可视线所覆盖的框,每个框高得和行框一样: 包裹的线有数个. 一段的后行,每一段的文字都显示 |
| 代码块的行 | 在街区的行 `<pre>`,突出显示或不显示 |
| 使用一个组件, 代码块一个组件绘图, 数学, 图像, 主题断开, 提醒的第一行: 页面上没有自己的文本 | 其范围所绘制的框, 在其范围开始的线上; 其之后的线条, 在其内部, 没有自己画的线条 |
| 只画什么: 空白行,前题,定义,链接定义, 容器的关闭行, 表的分隔行, 代码块的栅栏 | 离开,让地沟留下空白 |

**找到一段的后行.** 一个文本节点按处理器给它的文本保存,一个软行中断为 `\n`因此,一个节点的第三行文字跟随它的第二行 `\n`无论逃跑 实体 或标记线。 文本节点 `\n`s不匹配它的行,例如其值有行折的插值,只将它开始的行放入. 线起于内线标记内的地方(`**bold** text`),它的第一个角色是标记所绘制的第一个角色.

**沟渠所见.**

-   **线条可以共享可视线:** 柔软的换行符显示为空格,所以一段落的行3和行4经常出现在一行的页面上: 三是最后一格和四同为一格 `y`4是从3的终点开始的 地沟会显示第一个,或者两者兼有;一个标记一行的工具会标记它的矩.
-   **一个地方是第一个显示:** 迭代次数 `each`,它画出相同的行,第一个;其文字被隐藏的行(已关闭) `<details>`,一个断点 `hide`,一个组件的倒置而不显示)没有位置,除非它的另一幅图显示.
-   **位置跟随页面,而不是文本:** a 脚注的定义同其清单放在页后。 内容滚动在自有的盒子内(一个比页面更宽的代码块)放置在它的位置上,它可能位于盒子可见的部分外.

**页面移动时.** `onLayout` 当一个成像或相片被画出后,当页面根或其中的任何块改变大小(一个组件大小,一个装入的图像,一个报告其高度的框架),以及当字体完成加载时,就叫它。 它说,地方可能已经移动了,而不是页面已经移动了:一个其组件不断增长的页面再次调用. 等它停下来 [沙盒的车 `settled`](https://npmcn.com/package/%40compmd/sandbox/README.md),用于测试和印刷.

**其所限.** 在组件本身的DOM中,没有什么比组件更精细的了:它的线条在第一次画完之后没有自己的线条,一个组件在自己的框架里制造的东西也一样. 无出处之树无行相. 虽然该页面保留了块的最后良好渲染(第3条 _无效的文本_),该块的行画什么也没有,因为它的文本是更古老的文本.

**页面的生成器.** 每行在到达时都会被测量,所以一个发电机会保留在一指向或一指向上 `layout` 给出新页的从此开始的位置; 再次询问每张地沟图. `firstLineShown` 上面是主机的要知道,例如它绘制的最后一个数字的行在显示的上方.

通过一个框架, `frame.lines(from?)` 在帧的页面中, 帧按主机的回路进行分批计量, 以相同方式生成一个同步生成器(`for await`),以及 `frame.on("layout", …)` 称为 `onLayout` 将是(_在一个框架_页:1.

## 在一个框架

页面运行在一个框架内,它的呼叫器供应,例如沙箱式的iframe,一个端口携带树木进入和 `set` 呼唤。 两端都取取一个呼叫器所制造的端口,所以一个其沙盒已经有一个通道可以将一个接上来. A 类 `MessagePort` 是端口; 任何桥梁 `postMessage` 一个信息听器 适合在一个小适配器后面.

```ts
// in the host page
const { port1, port2 } = new MessageChannel();
iframe.contentWindow.postMessage("compmd", "*", [port2]);
const frame = connectFrame(port1);                 // from "@compmd/render/frame"
frame.on("set", ({ input, value }) => processAgain({ [input]: value }));
frame.on("error", ({ reason, component }) => report(reason, component));   // missing, or threw (W118)
frame.render(tree, change);
frame.splice(splices, change);                    // each a Splice, or a processor's JSON text of one
frame.reveal(offset);                             // scroll the frame's page to what the text at offset drew
const boxes = await frame.rectsAt(offset);        // its boxes, in the frame's viewport
frame.point(true);                                // report the source of what the reader clicks
frame.on("pointed", ({ source }) => moveCaret(source.start.offset));
frame.on("layout", async () => {
  for await (const { line, rects } of frame.lines()) place(line, rects);   // where each line is, in the frame's page
});

// inside the frame
addEventListener("message", ({ ports: [port] }) => serveFrame(port, { container: document.body, components }));
```

要帧的主机 : `render {tree, change?}`, (中文(简体) ), `splices {splices, change?, replace?}`, (中文(简体) ), `theme {tokens}`, (中文(简体) ), `reveal {offset}`, (中文(简体) ), `rects {id, offset}`, (中文(简体) ), `point {on}`, (中文(简体) ), `lines {id, from, count}`处理器给出的JSON文本(`@compmd/processor`是因为 `OpenDocumentJson`)),一个主机传递到未读:张贴的文本被一并复制,被帧解析一次. `replace` 说第一个插图是一棵空树,就像再次打开文档之后一样. 帧忽略了其他任何消息,所以一个主机可以在同一个端口上自行发送,就像一个编辑器用组件来编译一样. 要主机的框架 : `ready {version}`, (中文(简体) ), `set {input, value}`, (中文(简体) ), `error {reason, component?, use?, message}`, (中文(简体) ), `recovered {component, use}`, (中文(简体) ), `rendered {ms}` (在画了画后), `rects {id, rects}` (答复: `rects` 成员名单 `id`,每个 `{x, y, width, height}` ),以及,在 `point {on: true}`, (中文(简体) ), `pointed {source}` 为页面中的每次点击; `lines {id, lines, done}` (答复: `lines`: 最多 `count` 从行 `from`,每个 `{line, rects}` 在框的页中,以及是否有更多的; `frame.lines()` 要求下一个批次,随着它的循环进行, 并且没有任何一个停止, `layout {}` (截至 `onLayout`和 `drawn {seen}` (截至 `page.drawn()` 决议,第一个 `seen` 制作并切换取的相框)。 主机的消息等待 `ready` 使用本协议的版本(4,与 `lines`, (中文(简体) ), `layout` 财务报告和审定财务报表 `drawn`),因为一个主机页面及其框架可能会被分开部署. 组件代码保留在框中:模块无法被发布.

**页面来自哪里,通过框架.** 主机无法到达帧的元素,所以帧的末端做什么 `elementsAt` 财务报告和审定财务报表 `sourceOf` 将: `reveal(offset)` 滚动画框的页面,并标出里面的文字, `rectsAt(offset)` 以其框解决(一旦连接关闭,则无) `point(true)` 有框架报告,显示每次点击的来源,因为 `pointed`。 。 。 . `lines()` 给出每行在帧页面中的位置,一次批次(一旦连接关闭即结束),以及 `layout` 说何时再问. 一个帧的代码可能是不信任的,所以 `connectFrame` 仅传出一个精致的 `source`,是数字的框,是1的整行数字,是数字的矩形.

**使时间段自成一体的组件.** `rendersSlots(mount)` 使组件用于 `components` 制造器的槽不会使: `mount` 获得该用途的节点,其槽为扩展节点,文档的输入,以及其 `update` 再来一次 沙盒用它来做一个用途,它的槽在使用自己的框架内([`@compmd/sandbox`](https://npmcn.com/package/%40compmd/sandbox/README.md)); 代码块的渲染器得到它的叶子,而块的文字是 `code`。 。 。 .

## 内置物的参考渲染

HTML 和 CSS 此软件包为内置内容所写的是参考渲染 spec §13.1 调用信息 。 每个布局参数是指它命名的 CSS 属性(§9.4);样式表是每个文档一个(一个已构建的样式表,一个沙盒的 CSP 允许的),每个样式块得到一个类.

| 内建 | HTML 语言 | 支助科 |
| --- | --- | --- |
| `box` (和 `stack`, (中文(简体) ), `row`, (中文(简体) ), `grid`,扩展到它) | `<div class="compmd-box compmd-bN">` 抚养子女 | 其布局和通用参数 `.compmd-bN`; 符号为 `var(--compmd-space-m, 1rem)` 例如(§9.4);断点参数 `@container (min-width: 768px) { … }`· ; `show` 财务报告和审定财务报表 `hide` 作为 `display: none` 其首个孩子的挡板启动比值和最后一个孩子的挡板端比值被修剪,如 `margin-trim: block` 将会,所以它的粘接是其边缘的所有空间(同样在组件的框和插槽项中) |
| 块使用断点的框 | 添加 `compmd-container` | `container-type: inline-size` |
| 装满了的盒子`fill`(中文(简体) ) | 添加 `compmd-fills` | `display: flex; flex-direction: column`,块 `flex-grow: 1` |
| 带有位置的块( A)`inset-*` 没有 `auto`(中文(简体) ) | —— 说 | `position: absolute` 及其内置;每个框 `position: relative` |
| 主机语言部分 | `<div class="compmd-component compmd-bN">` (数量) `target`中,每个槽项 `<div class="compmd-item">` | 其框上常见的参数 |
| 一个输入组件 | `<label class="compmd-box compmd-input">` 与 `<span class="compmd-input-label">`,在第一个结肠之前倒下(`From: today` 给 `From`然后,由于下文是默认的 `<input type="date">`, (中文(简体) ), `number`, (中文(简体) ), `text`, (中文(简体) ), `checkbox`,或 `<select>` 与enum的成员 | 标签和控件并排 |
| 什麽 `reveal` 显示 | 添加 `compmd-revealed` 1.5 s 时数 | 大纲 `--compmd-accent` |
| 在途中使用某个部件(`componentPending`, 第4.5节) | 倒计时 `<div class="compmd-pending" aria-busy="true">`页:1 `<span>` ; 在主机组件的插槽中, 其条目 `component` 实值 `{name, params: {}, pending: true}` | 有点淡出`opacity: 0.6`)),主机可能会重排 |
| 警报 | `<div class="compmd-alert compmd-alert-note" role="note">` 与 `<p class="compmd-alert-title">Note</p>` 第一个 | 开始边缘的规则 |
| 引用 | `<blockquote class="compmd-quote">` | 起始边缘的更轻规则 |
| 严格清单`spread: false`(中文(简体) ) | `<ul class="compmd-tight">`, (中文(简体) ), `<ol class="compmd-tight">` | 它的段落没有边距, 因为 HTML 使列表很紧, 没有 `<p>` |
| 任务列表项目 | `<li class="compmd-task">` 与 `<input type="checkbox" disabled>` 第一个 | 无子弹; 第1行的框 |
| 脚注 | `<sup><a href="#compmd-fn-1" id="compmd-fnref-1">1</a></sup>`,并在结尾 `<section class="compmd-footnotes"><hr><ol><li id="compmd-fn-1">…</li></ol></section>` | 较小的文本 |
| 显示为代码的代码块 | `<pre><code class="language-js">`,没有课的块没有语言 `highlight`,其标志在 `<code>`,正如亮点书写的 | —— 说 |
| 没有渲染器的数学 | `<code class="language-math math-inline">`, (中文(简体) ), `<pre><code class="language-math math-display">` | —— 说 |
| 一张桌子 | `<thead>` 第一行,对齐为 `compmd-align-left`, (中文(简体) ), `-center`, (中文(简体) ), `-right` | `text-align` |
| 原始 HTML 语言 | `details`, (中文(简体) ), `summary`, (中文(简体) ), `sub`, (中文(简体) ), `sup`, (中文(简体) ), `kbd`, (中文(简体) ), `br`, (中文(简体) ), `img` (单位:千美元)`src`, (中文(简体) ), `alt`和 `a` (单位:千美元)`href`) 安全 URL; 其他标签显示为文本 | —— 说 |

```md
::: grid {min=14rem gap=m}
```

```html
<div class="compmd-box compmd-b3">…</div>
<!-- .compmd-b3 { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: var(--compmd-space-m, 1rem); } -->
```

## 测试

-   **[`src/vocabulary.test.ts`](https://npmcn.com/package/%40compmd/render/src/vocabulary.test.ts)数字 :** 它的样式正是处理器的(`conformance/params.json`),而他们的每个符号都得到CSS;一个符号CSS按它被列在上面.
-   **单位测试** 旁边的代码:样式、原始 HTML 、 源图像、 密钥、 组件层、 页面及其相接处( 块保持、 几个顺序、 脚注、 链接、 标题、 原始 HTML 横跨块、 输入、 前题) 、 区域容器、 框架协议.
-   **[`test/identity.test.ts`](https://npmcn.com/package/%40compmd/render/test/identity.test.ts)数字 :** 每编辑一个有状态的组件的文档(上面、内部和段落中、内部) `each`,添加、去除并粘贴块、撤消、添加记录、移动块),检查哪些组件保持其实例和状态。 每一棵树都与整棵树相通,并有花序相通,各有一页.
-   **[`test/invalid.test.ts`](https://npmcn.com/package/%40compmd/render/test/invalid.test.ts)数字 :** 一个未密闭的容器,一个半成文的表达式,一个半型元件线和破碎的前物,打出并完成,有整棵树和花序.
-   **[`src/source.test.ts`](https://npmcn.com/package/%40compmd/render/src/source.test.ts), (中文(简体) ), [`test/source.test.ts`](https://npmcn.com/package/%40compmd/render/test/source.test.ts)数字 :** 页面的出处是: 地图到什么的每个规则,相接点,一个区域, `reveal`;每一次编辑固定装置时,都有一页由相接相接而来的最新页面,以图示每个元素和每个相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相.
-   **[`test/conformance.test.ts`](https://npmcn.com/package/%40compmd/render/test/conformance.test.ts)数字 :** 组合中的每棵被扩展的树,作为每一块的一页和一区域,都有相同的文字.
-   **[`test/bindings.test.ts`](https://npmcn.com/package/%40compmd/render/test/bindings.test.ts)数字 :** 反应和Svelte绑定.

装入 [`test/fixtures/`](https://npmcn.com/package/%40compmd/render/test/fixtures/) 每个树都有其文字、诊断和编辑。 它们是用一个原型处理器制造的,并将再次使用 `compmd` 处理器.

## 常见问题

### @compmd/render 是什么？

Renders a CompMD 扩展树作为活页:Markdown,布局,输入和主机语言组件通过主机合同\.

### 如何安装 @compmd/render？

在项目目录运行 npm install @compmd/render，或使用 pnpm add / yarn add / bun add。

### @compmd/render 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @compmd/render 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @compmd/render 可以商用吗？

@compmd/render 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @compmd/render 的下载量有多少？

根据 npm 官方下载统计，@compmd/render 在 2026/10/11 – 2026/11/09 这 30 天内被下载 2,337 次，日均约 78 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @compmd/render 还在维护吗？

最新版本 0\.6\.0 发布于 2026/11/09（今天）；至今共发布 10 个版本，其中过去 12 个月发布了 10 个；首次发布于 2026/10/30。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

