# @datocms/content-link 中文文档

规范地址：https://npmcn.com/package/%40datocms/content-link/

版本：0\.3\.23
npm 元数据更新时间：2026-06-23T10:43:59.917Z
中文译文更新时间：2026-11-11T15:33:36.722Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40datocms/content-link
原文对照：https://npmcn.com/package/%40datocms/content-link/?lang=original
项目主页：https://github.com/datocms/content-link#readme
源码仓库：https://github.com/datocms/content-link

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

- 包体积（解压后）：711 kB，42 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18
- 运行依赖：0 个
- 首次发布：2025-11-07T14:00:33.804Z
- 最新版本发布：2026-06-23T10:43:59.601Z
- 近 30 天下载量：267047（2026-10-12 至 2026-11-10，npm 官方下载统计）
- 已发布版本数：32（近 12 个月 31 个）

## 中文简介

为 DatoCMS 视觉编辑所设置的轻量级库上覆和内容链接.

## 安装

```sh
npm install @datocms/content-link
```

也可以使用：`pnpm add @datocms/content-link`、`yarn add @datocms/content-link`、`bun add @datocms/content-link`

## README

# DatoCMS 内容链接

[![npm version](https://img.shields.io/npm/v/@datocms/content-link.svg)](https://www.npmjs.com/package/@datocms/content-link) [![License: MIT](https://img.shields.io/npm/l/@datocms/content-link.svg)](https://npmcn.com/package/%40datocms/content-link/LICENSE)

为DatoCMS项目点击到编辑的覆盖. 平台和框架不可知论,两个功能需要设置.

```bash
npm install @datocms/content-link
```

## 快开始

### 1\. 启用内容链接获取内容

确保你通过 `contentLink` 财务报告和审定财务报表 `baseEditingUrl` 选项:

```ts
import { executeQuery } from "@datocms/cda-client";

const result = await executeQuery(query, {
  token: process.env.DATO_API_TOKEN,
  contentLink: 'v1',
  baseEditingUrl: 'https://acme.admin.datocms.com', // <- URL of your DatoCMS project (https://<YOUR-PROJECT-NAME>.admin.datocms.com)
});
```

### 2\. 启用自动点击到编辑的覆盖

```ts
import { createController } from '@datocms/content-link';

const controller = createController();
controller.enableClickToEdit();
```

**说明:** 你也可以跳过电话 `enableClickToEdit()` 并暂时通过按住 **备选案文/备选** 键。 模式在按键被持有时会激活,发布时会自动禁用.

这就是你需要的 大多数项目! 如果你看到覆盖和深层链接打开正确的记录,你的设置就完成了!

* * *

### `createController(options?)`

```ts
import { createController } from '@datocms/content-link';

// Minimal (no options required)
const controller = createController();

// With options
const controller = createController({
  // Optional: limit scanning/observation to this root instead of the whole document.
  // Can be a ShadowRoot or a specific container element.
  root: document.getElementById('preview-container'),

  // Optional: strip stega-encoded invisible characters from text content (default: false)
  stripStega: false,

  // Optional: silence Content Link console warnings (default: false)
  silenceWarnings: true,

  // Optional: hue (0–359) of the overlay accent color (default: 17, orange)
  hue: 200
});

// Control click-to-edit overlays
controller.enableClickToEdit();       // turn click-to-edit overlays on
controller.enableClickToEdit({        // with visual flash highlighting all editable elements
  scrollToNearestTarget: true         // optionally scroll to nearest editable if none visible
});
controller.disableClickToEdit();      // turn click-to-edit overlays off
controller.isClickToEditEnabled();    // check if click-to-edit is currently enabled
controller.isDisposed();              // check if disposed
controller.dispose();                 // permanently tear down and clean up (controller becomes inert)
```

返回管理 DOM 印章和点击到编辑的覆盖的控制器.

**选项 :**

-   `root?: ParentNode`: 将扫描限制为特定容器(默认: `document`(中文(简体) )
-   `hue?: number`: 覆盖口音颜色的色调(0–359) (默认: `17`,橙色) (中文(简体) ). 库会自动计算出一个轻度值, 保证在任何色调时可以读取上覆贴标签的可读白文本 .
-   `stripStega?: boolean`: 印出后是否从文本内容中去除已编码的已忽略不计的字符( 默认 ): `false`) (中文(简体) ). Stega将无形,零宽的UTF-8字符嵌入到文本内容中来编码编辑元数据.
    -   何时 `false` (默认): Stega 编码保存在 DOM 中,允许在同一页上处理和再创建控制器. 隐形人物不会影响显示,而是保留了真理的来源.
    -   何时 `true`: Stega 编码从文本节点中永久去除,提供干净 `textContent` 方案准入。 然而,由于编码丢失,在同一页上重新创建一个控制器将无法检测元素.
-   `silenceWarnings?: boolean`:是否在控制台中压制内容链接诊断警告(默认 : `false`) (中文(简体) ). 设定为 `true` 只有在您已审查并接受警告来源时.

**控制器方法:**

-   `enableClickToEdit(flashAll?: { scrollToNearestTarget: boolean })`: 打开点击到编辑的覆盖( 允许点击元素打开编辑器) 。 可选通过 `flashAll` 以简略地突出所有可编辑的具有动画效果的元素,并滚动到最近的没有可见的元素.
-   `disableClickToEdit()`: 将点击到编辑的封面关闭(DOM 印花继续)
-   `isClickToEditEnabled()`: 回归 `true` 如果当前启用了点击到编辑
-   `isDisposed()`: 回归 `true` 如果控制器已被处理
-   `dispose()`:永久断开观察并清理. 处理后, 控制器无法重新启用; 需要时创建新控制器
-   `flashAll(scrollToNearestTarget?: boolean)`: 简要地突出所有可被编辑的有动画效果的元素. 可选滚动到最接近的可编辑元素, 如果没有可见.

**键盘快捷键 :**

-   **备选密钥**: 按住以暂时启用/可禁用点击到编辑模式. 此切换当前状态, 并在键被放出时返回 .

**说明:** DOM 标记( 检测和标记可编辑元素) 在创建控制器时自动运行并持续到 `dispose()` 名为. 点击到编辑的覆盖是独立的,必须明确启用 `enableClickToEdit()`。 。 。 .

* * *

## Web 预览插件集成

当您的网站运行于该平台的视觉编辑模式 [Web 预览插件](https://www.datocms.com/marketplace/plugins/i/datocms-plugin-web-previews),控制器会自动与插件建立双向通信.

这个连接是 **完全自动** ,不需要配置。 如果您的预览没有在 iframe 中运行, 或连接失败, 库会轻而易举地回到新标签中打开编辑 URL .

### 客户端路由支持

如果您的网站使用客户端路由( 如 Next.js, React Router等), 您需要设置与插件的双向通信 :

```tsx
// Next.js App Router example
'use client';

import { createController } from '@datocms/content-link';
import { useRouter, usePathname } from 'next/navigation';
import { useEffect } from 'react';

export default function PreviewPage() {
  const router = useRouter();
  const pathname = usePathname();

  useEffect(() => {
    const controller = createController({
      // Handle navigation requests from the plugin
      onNavigateTo: (path) => {
        router.push(path);
      }
    });

    return () => controller.dispose();
  }, [router]);

  useEffect(() => {
    // Notify the plugin when the URL changes
    controller?.setCurrentPath(pathname);
  }, [pathname]);

  return <YourPageContent />;
}
```

**可用选项 :**

-   `onNavigateTo?: (path: string) => void`: 当 Web 预览插件请求导航到不同的 URL 时引用回调

**可用方法 :**

-   `setCurrentPath(path: string)`: 通知当前 URL 的 Web 预览插件

* * *

## 高级用途

### 主计长的生命周期和斯德加保存

默认情况下,控制器会在DOM中保存被编码为stega-encode的隐形字符. 这使得您可以在同一页上安全地处理和再造控制器,同时不丧失检测可编辑元素的能力:

```ts
// Create initial controller
const controller1 = createController();
controller1.enableClickToEdit();

// Later, dispose it
controller1.dispose();

// Create a new controller - it will still find all editable elements
const controller2 = createController();
controller2.enableClickToEdit();
```

这对于:

-   安装/安装的测试方案
-   导航时需要重新创建控制器的单页应用程序
-   开发期间的热重装
-   任何需要控制器在不重新装入页面的情况下重新启动的情景

如果程序访问需要干净的文本内容(没有隐形stega字符),请使用 `stripStega: true`然而,请注意,这可以永久去除 Stega 编码,防止控制器的娱乐:

```ts
const controller = createController({ stripStega: true });

// After disposal, creating a new controller won't find elements
controller.dispose();
const controller2 = createController(); // Won't detect editable elements
```

### 带有闪光提示的视觉反馈

您可以以两种方式显示页面上所有可编辑元素的用户:

**1\. 启用点击到编辑模式时:**

```ts
controller.enableClickToEdit({
  scrollToNearestTarget: true
});
```

**2\. 作为一种独立方法:**

```ts
// Highlight all editable elements
controller.flashAll();

// Highlight and scroll to nearest editable if none visible
controller.flashAll(true);
```

这将:

1.  简要地突出所有带有动画淡出/出动画效果的可编辑元素(使用交错动画)
2.  若为 `scrollToNearestTarget` 实值 `true` 而目前没有可编辑元素可见于视图端口,自动滚动到最近的可编辑元素

这对于:

-   将用户输入编辑体验
-   帮助编辑者快速识别可以编辑的内容
-   导航到长页面上可编辑的内容

### 数据属性参考

此库使用多个 `data-datocms-*` 属性。 有些人是 **指定开发者** (你把他们加在你的标记上) **图书馆管理** (DOM印花时会自动加入). 这里有一个完整的参考文献.

#### 开发者指定属性

这些属性由您在模板/ 组件中添加, 以控制可编辑区域的行为 .

##### `data-datocms-content-link-url`

手动将一个元素标为可编辑,并带有明确的编辑 URL。 用于不能包含stega编码的非文本字段(booleans,数字,日期,JSON). 建议采用的方法是: `_editingUrl` 字段已载入所有记录 :

```graphql
query {
  product {
    id
    price
    isActive
    _editingUrl
  }
}
```

```tsx
<span data-datocms-content-link-url={product._editingUrl}>
  ${product.price}
</span>
```

##### `data-datocms-content-link-source`

随附stega-encoded元数据而无需将其变成内容. 用于无法包含文本的结构元素( 如 `<video>`, (中文(简体) ), `<audio>`, (中文(简体) ), `<iframe>`或当显式文本中的stega编码有问题时:

```tsx
<div data-datocms-content-link-source={video.alt}>
  <video src={video.url} poster={video.posterImage.url} controls />
</div>
```

值必须是 stega 编码字符串( API 中的任何文本字段都会工作) 。 库从属性值中解码出 stega 元数据,并使元素可以点击来编辑.

##### `data-datocms-content-link-group`

将可点击区域扩展为父元素。 当库遇到stega-encoded的内容时,默认它使得文本节点的直系父可以点击来编辑. 将这个属性添加到祖先,使得祖先可以点击目标:

```html
<article data-datocms-content-link-group>
  <h2>Title with stega</h2>
  <p>Description with no stega</p>
</article>
```

在这里,点击任何地方在 `<article>` 打开编辑器,而不是要求用户精确点击 `<h2>`。 。 。 .

**重要内容:** 一个组只应该包含一个stega编码源. 如果多个 stega 字符串解决到同一组, 库会记录一个相撞警告, 只有最后的 URL 获胜 .

##### `data-datocms-content-link-boundary`

停止向上 DOM 向上 寻找一个 `data-datocms-content-link-group`,使 Stega 的元素成为可点击的目标。 这将创建一个不会合并成父组的独立可编辑区域(参见 [团体和边界的解析方式](https://npmcn.com/package/%40datocms/content-link/#readme-how-group-and-boundary-resolution-works) 详情如下:

```html
<div data-datocms-content-link-group>
  <h1>Title with stega (URL A)</h1>
  <section data-datocms-content-link-boundary>
    <span>Text with stega (URL B)</span>
  </section>
</div>
```

没有边界,点击"Text with Stega"将打开URL A(外组). 与边界 `<span>` 成为可点击的目标打开 URL B.

边界也可以直接放在包含 stega 文本的元素上:

```html
<div data-datocms-content-link-group>
  <h1>Title with stega (URL A)</h1>
  <span data-datocms-content-link-boundary>Text with stega (URL B)</span>
</div>
```

在这里 `<span>` 有边界并直接包含 stega 文本,所以 `<span>` 本身成为可点击的目标(因为起始元素和边界元素相同).

#### 库管理属性

这些属性由库在 DOM 印花时自动添加. 不需要自己添加,但可以在CSS或JavaScript中瞄准它们.

##### `data-datocms-contains-stega`

添加到其文本内容包含stega-encoaded隐形字符的元素中. 此属性仅在 `stripStega` 实值 `false` (默认),因为 `stripStega: true` 全部删除字符。 对 CSS 工作变通有用——零宽字符有时会导致出乎意料的字母间隔或文本外溢:

```css
[data-datocms-contains-stega] {
  letter-spacing: 0 !important;
}
```

##### `data-datocms-auto-content-link-url`

自动添加到库已确定为可编辑目标的元素(通过stega解码和组/边界解析). 包含已解析的编辑 URL.

这是开发者的自动对应器 `data-datocms-content-link-url`。图书馆添加 `data-datocms-auto-content-link-url` 只要它能从 Stega 编码中提取编辑 URL,则 `data-datocms-content-link-url` 用于不能嵌入stega编码的非文本字段(booleans,数字,日期等)。 两个属性都由点击到编辑的覆盖系统来决定哪些元素可以点击以及它们链接到哪里.

### 团体和边界的解析方式

当库遇到一个元素内部的stega-encode内容时,它从该元素上走出DOM树:

1.  如果发现 `data-datocms-content-link-group`,它停止和邮票 **那个** 元素作为可点击的目标.
2.  如果发现 `data-datocms-content-link-boundary`,它停止并盖章 **启动元素** 作为可点击的目标——防止进一步转弯.
3.  如果它到达了根 没有找到,它会盖上 **启动元素**。 。 。 .

以下是一些具体的例子来说明:

**例1:被封杀的群体**

```html
<div data-datocms-content-link-group>
  <h1>Title with stega (URL A)</h1>
  <div data-datocms-content-link-group>
    <p>Paragraph with stega (URL B)</p>
  </div>
</div>
```

-   **"与斯德加谈起"**: 从上走起 `<h1>`,找到外组 + **外部 `<div>`** 可点击(打开 URL A).
-   **"与斯德加的段落"**: 从上走起 `<p>`,首先找到内部组 **内 `<div>`** 可点击(打开 URL B)。 外组从未到达.

每个巢组会创建独立的可点击区域. 最内层的团体总是为自己的内容取胜.

**例2:防止群体传播的边界**

```html
<div data-datocms-content-link-group>
  <h1>Title with stega (URL A)</h1>
  <section data-datocms-content-link-boundary>
    <span>Text with stega (URL B)</span>
  </section>
</div>
```

-   **"与斯德加谈起"**: 从上走起 `<h1>`,找到外组 + **外部 `<div>`** 可点击(打开 URL A).
-   **"文字与斯德加"**: 从上走起 `<span>`,点击 `<section>` 边界 ~ 横行的站点 **`<span>`** 本身成为可点击(打开 URL B) 。 外组未接通.

**例3:一组内的边界**

```html
<div data-datocms-content-link-group>
  <p>Main content with stega (URL A)</p>
  <div data-datocms-content-link-boundary>
    <p>Isolated content with stega (URL B)</p>
  </div>
</div>
```

-   **"主要内容与斯德加"**: 从上走起 `<p>`,找到外组 + **外部 `<div>`** 可点击(打开 URL A).
-   **"孤立的内容与斯德加"**: 从上走起 `<p>`,击中边界 ~ 横倒站 **`<p>`** 本身成为可点击(打开 URL B) 。 外组未接通.

**例4: 多个无组合的stega字符串( 曲线警告)**

```html
<p>
  Text with stega (URL A)
  More text with stega (URL B)
</p>
```

两个被编码的字符串都一致 `<p>` 键。 库记录一个控制台警告, 最后的 URL 获胜 。 为了解决这个问题,将每个内容包裹在自己的元素中:

```html
<p>
  <span>Text with stega (URL A)</span>
  <span>More text with stega (URL B)</span>
</p>
```

如果需要警告并且您接受了模糊的目标,您可以将内容链接警告与 `createController({ silenceWarnings: true })`。这只会压制控制台的警告;不会改变基本的盖章行为.

### 结构 文本字段

结构 文本字段需要特别注意,因为 Stega 编码是如何在其中工作的:

-   DatoCMS API 将 Stega 信息编码在一个单曲内 `<span>` 在结构化文本输出中。 如果没有任何配置,只有这个小跨度才能被点击.
-   结构 文本字段可以包含 **嵌入区块** 财务报告和审定财务报表 **内置记录**,每个都带有各自的编辑URL,该URL应该在编辑器中打开不同的记录.

以下规则如下:

#### 第1条: 始终将结构化文本组件包成一组

这使得整个结构化的文本区域可以点击,而不只是微小的stega-encoded跨度:

```tsx
<div data-datocms-content-link-group>
  <StructuredText data={page.content} />
</div>
```

#### 第2条:将嵌入式块和内入式记录包入边界

嵌入式块和内入式记录有自己的编辑URL(指向块/记录). 如果没有边框,点击它们就会泡到母组并打开结构化的文本字段编辑器。 添加 `data-datocms-content-link-boundary` 防止它们合并为母组:

```tsx
<div data-datocms-content-link-group>
  <StructuredText
    data={page.content}
    renderBlock={(block) => (
      <div data-datocms-content-link-boundary>
        <BlockComponent block={block} />
      </div>
    )}
    renderInlineRecord={(record) => (
      <span data-datocms-content-link-boundary>
        <InlineRecordComponent record={record} />
      </span>
    )}
  />
</div>
```

通过这个设置:

-   单击正文(段落、标题、列表)打开 **结构化文本字段编辑器**
-   单击嵌入式块或内入式记录打开 **那个唱片的编辑器**

* * *

## 低级公用事业

```ts
import { decodeStega, stripStega, revealStega } from '@datocms/content-link';

// Decode a raw string that may contain stega
const info = decodeStega(someString);
// Returns: { origin: string, href: string } | null

// Remove stega characters for display
const clean = stripStega(someString);

// Make stega visible for debugging (works with any value, including full GraphQL responses)
const debug = revealStega(graphqlResponse);
console.log(JSON.stringify(debug, null, 2));
```

**`decodeStega(input: string)`**

-   解码字符串中的已编码元数据
-   回返 `{ origin: string, href: string }` 如果stega被发现, `null` 否则
-   用于从 stega 编码内容中提取编辑 URL

**`stripStega(input: any)`**

-   使用任意数据类型:字符串、对象、阵列和原始数据
-   转换输入到 JSON, 删除所有已编码的区段 `VERCEL_STEGA_REGEX`,然后解析为原始类型
-   返回清除后的数据, 不包含无形的 Stega 字符

**`revealStega(input: any)`**

-   工作与任何数据类型,就像 `stripStega`
-   而不是去除 Stega,而是用可见的 `[STEGA:/editor/item_types/…]` 标记
-   用于调试查看哪些字符串带有可视编辑元数据

```ts
// Works with strings
stripStega("Hello\u200EWorld") // "HelloWorld"

// Works with objects
stripStega({ name: "John\u200E", age: 30 })

// Works with nested structures - removes ALL stega encodings
stripStega({
  users: [
    { name: "Alice\u200E", email: "alice\u200E.com" },
    { name: "Bob\u200E", email: "bob\u200E.co" }
  ]
})

// Works with arrays
stripStega(["First\u200E", "Second\u200E", "Third\u200E"])

// Reveal stega in a full GraphQL response for debugging
revealStega({
  blog: {
    title: "Hello World\u200E",
    author: { name: "Alice\u200E" }
  }
})
// {
//   blog: {
//     title: "Hello World[STEGA:/editor/item_types/123/items/456]",
//     author: { name: "Alice[STEGA:/editor/item_types/789/items/012]" }
//   }
// }
```

## 解决问题

-   **没有覆盖**: 确保您的获取请求包含 `contentLink` 财务报告和审定财务报表 `baseEditingUrl` 选项. `baseEditingUrl` 设置为您的 DatoCMS 项目管理 URL( 例如, ), `https://<YOUR-PROJECT-NAME>.admin.datocms.com`) (中文(简体) ). sega-encoded元数据只有在这些选项出现时才包含在回复中. 还有 确保你打过电话 `enableClickToEdit()` 在控制器上.
-   **无法单击元素**: DOM 印花自动运行,但点击到编辑覆盖需要通过 `enableClickToEdit()`。 。 。 .
-   **未更新的重叠**: Mutation Observers 自动检测到 DOM 变化并重新扫描. 如果你马上要替换DOM的大部分, 确保突变是可观察到的.
-   **Web 预览插件集成无效**: 插件连接只在预览运行在 Web 预览插件 iframe 内时才有效 。 在插件外, 编辑 URL 将在新标签中打开作为倒置 .
-   **主计长娱乐问题**:如果在同一页上处理并再创建一个控制器,第二个控制器只会找到元素,如果 `stripStega: false` (默认). 如果您以前使用过 `stripStega: true`, Stega 编码被永久去除,无法恢复。 在这种情况下,您需要重新装入页面或重新调取内容.
-   **Stega 编码引起的布局问题**:无形的零宽字符会导致出乎意料的字母间距或文本从容器中断出. 要解决这个问题,要么用 `stripStega: true`,或使用 CSS : `[data-datocms-contains-stega] { letter-spacing: 0 !important; }`。当 `stripStega: false` (默认).
-   **已知警告声**: 如果您已审查过警告源并想要保留当前标记, 请通过 `silenceWarnings: true` 改为 `createController()`。此选项可以默化内容链接警告,而不改变哪些元素被盖章.

## 许可证

麻省理工学院

## 常见问题

### @datocms/content-link 是什么？

为 DatoCMS 视觉编辑所设置的轻量级库上覆和内容链接\.

### 如何安装 @datocms/content-link？

在项目目录运行 npm install @datocms/content-link，或使用 pnpm add / yarn add / bun add。

### @datocms/content-link 支持 TypeScript 吗？

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

### @datocms/content-link 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @datocms/content-link 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @datocms/content-link 可以商用吗？

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

### @datocms/content-link 的下载量有多少？

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

### @datocms/content-link 还在维护吗？

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

