探索 Tiptap V3 的最新功能

目录扩展

版本下载量

TableOfContents 扩展允许您从文档中获取锚点列表,并传递每个锚点的重要信息(例如深度、内容及每个标题的唯一 ID,还包括每个锚点的激活状态和滚动状态)。这可用于您自行渲染目录。

安装

完成后,您可以从我们的私有注册表安装该扩展:

npm install @tiptap/extension-table-of-contents

设置

anchorTypes

您希望用于目录的节点类型。默认值为 ["heading"],但如果您创建自己的自定义标题扩展或扩展现有扩展并使用不同的名称,可以在此传递该名称。

默认值: ["heading"]

TableOfContents.configure({
  anchorTypes: ['heading', 'customAnchorType'],
})

getIndex

此选项可用于自定义项目索引的计算方式。默认情况下使用内部函数,但可以被覆盖以执行自定义逻辑。

TableOfContents.configure({
  getIndex: (anchor, previousAnchors, level) => {
    // 执行一些自定义逻辑,但在这个例子中我们将返回 1
    return 1
  },
})

我们提供了两个现成的函数——一个用于生成从 1 到 n 的线性索引,另一个用于生成从 1 到 n 的每个级别的层次索引。

import { getLinearIndexes, getHierarchicalIndexes } from '@tiptap/extension-table-of-contents'

// 生成线性索引
TableOfContents.configure({
  getIndex: getLinearIndexes,
})

// 生成层次索引
TableOfContents.configure({
  getIndex: getHierarchicalIndexes,
})

getLevel

此选项可用于自定义项目级别的生成方式。默认使用普通级别生成方式,检查标题元素的级别属性。如果您想自定义此项,例如要在标题生成中包含自定义锚点,可以这样做。

TableOfContents.configure({
  getLevel: (anchor, previousAnchors) => {
    // 执行一些自定义逻辑,但在这个例子中我们将返回 1
    return 1
  },
})

getId

生成每个标题唯一 ID 的构建函数。在参数中,您可以访问标题的文本内容(例如,您想根据标题的文本内容生成 ID)。

默认值是一个使用 uuid 包生成唯一 ID 的函数。

默认值: () => uuid()

// 这里我们使用一个虚构的 "slugify" 函数
// 您可能还应在 slug 中添加唯一标识符
TableOfContents.configure({
  getId: (content) => slugify(content),
})

scrollParent

您希望附加到的滚动父元素。这用于确定当前活动的标题或已经滚动过的标题。默认情况下,这是一种返回窗口的回调函数,但您可以在此处传递返回任何 HTML 元素的回调。

默认值: () => window

// 例如编辑器的 DOM 元素本身是滚动元素
TableOfContents.configure({
  scrollParent: () => editor.view.dom,
})

onUpdate

使用此扩展时必须设置的最重要选项。这是一个回调函数,每当目录更新时被调用。您可以访问一个标题数据的数组(见下文),可以用其来渲染自己的目录。

要渲染目录,您可以通过任何您想要的方式进行渲染。您可以使用像 Vue、React 或 Svelte 这样的框架,或者您可以使用像 Handlebars 或 Pug 这样的简单模板引擎。您还可以使用简单的 document.createElement 来渲染目录。

您可以传递第二个参数,以获取这是否是 ToC 数据的初始创建步骤的信息。

默认值: undefined

// 使用原生 JS
const tocElement = document.createElement('div')
document.body.appendChild(tocElement)

TableOfContents.configure({
  onUpdate: (anchors, isCreate) => {
    tocElement.innerHTML = ''

    if (isCreate) {
      console.log('这是 ToC 数据的初始创建步骤')
    }

    anchors.forEach((anchor) => {
      const anchorElement = document.createElement('div')

      anchorElement.innerHTML = anchor.content
      anchorElement.dataset.id = anchor.id
      anchorElement.dataset.depth = anchor.depth
      anchorElement.dataset.active = anchor.active
      anchorElement.dataset.scrolled = anchor.scrolled

      tocElement.appendChild(anchorElement)
    })
  },
})
// 使用 react
const [anchors, setAnchors] = useState([])

// 在 useEditor hook 内部,您可以做类似的事情:
TableOfContents.configure({
  onUpdate: (anchors) => {
    setAnchors(anchors)
  },
})
// 使用 vue
const anchors = ref([])

TableOfContents.configure({
  onUpdate: (anchors) => {
    anchors.value = anchors
  },
})

存储

content

当前文档的标题内容

editor.storage.tableOfContents.content

anchors

一个 HTML 节点的数组

editor.storage.tableOfContents.anchors

scrollHandler

滚动函数使用的 scrollHandler。不应更改或编辑,但可以用来手动在其他地方绑定此函数。

editor.storage.tableOfContents.scrollHandler()

scrollPosition

scrollParent 内的当前滚动位置。

editor.storage.tableOfContents.scrollPosition

锚点数组

存储或 onUpdate 函数返回的数组包括结构如下的对象:

{
  dom: HTMLElement // 此锚点的 HTML 元素
  editor: Editor // 编辑器
  id: string // 节点 id
  isActive: boolean // 此锚点当前是否活动
  isScrolledOver: boolean // 此锚点是否已经滚动过
  itemIndex: number // 当前级别上项目的索引
  level: number // 项目的当前级别 - 这可能与实际锚点级别不同,用于渲染从高到低的标题层次
  node: Node // 此锚点的 ProseMirror 节点
  originalLevel: number // 实际级别
  pos: number // 锚点节点的位置
  textContent: string // 锚点的文本内容
}

这应该为您提供足够的灵活性,以渲染您自己的目录。