初始化
This commit is contained in:
1 parent
34474bd5fc
commit
b638b541d0
3008 files changed
+837699
No files matched your search
@@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import type { Editor } from "@tiptap/react";
|
||||
|
||||
/** 文档目录中的一个标题项 */
|
||||
export interface OutlineHeading {
|
||||
/** React key + scroll-spy 标识,按 ProseMirror 位置生成 */
|
||||
id: string;
|
||||
/** 标题层级,仅保留 1~3 */
|
||||
level: 1 | 2 | 3;
|
||||
/** 标题纯文本 */
|
||||
text: string;
|
||||
/** 标题节点在 ProseMirror 文档中的位置,用于解析 DOM 元素 */
|
||||
pos: number;
|
||||
}
|
||||
|
||||
/** 仅纳入目录的最大标题层级(H1~H3) */
|
||||
const MAX_LEVEL = 3;
|
||||
/** 内容变化后重建目录的防抖间隔(ms) */
|
||||
const DEBOUNCE_MS = 200;
|
||||
|
||||
/**
|
||||
* 从 Tiptap 编辑器实时提取 H1~H3 标题,构成文档目录。
|
||||
*
|
||||
* 首次挂载立即构建一次;之后监听 `editor.on('update')`,按 DEBOUNCE_MS 防抖重建,
|
||||
* 避免逐字输入时频繁全量遍历。
|
||||
*/
|
||||
export function useDocumentOutline(editor: Editor | null): OutlineHeading[] {
|
||||
const [headings, setHeadings] = useState<OutlineHeading[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor) {
|
||||
setHeadings([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const compute = () => {
|
||||
const out: OutlineHeading[] = [];
|
||||
editor.state.doc.descendants((node, pos) => {
|
||||
if (node.type.name !== "heading") return true;
|
||||
const level = node.attrs.level as number;
|
||||
if (level >= 1 && level <= MAX_LEVEL) {
|
||||
out.push({
|
||||
id: `heading-${pos}`,
|
||||
level: level as 1 | 2 | 3,
|
||||
text: node.textContent.trim() || "(无标题)",
|
||||
pos,
|
||||
});
|
||||
}
|
||||
return true;
|
||||
});
|
||||
setHeadings(out);
|
||||
};
|
||||
|
||||
// 首次立即构建
|
||||
compute();
|
||||
|
||||
// 内容变化时防抖重建
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
const onUpdate = () => {
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(compute, DEBOUNCE_MS);
|
||||
};
|
||||
editor.on("update", onUpdate);
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
editor.off("update", onUpdate);
|
||||
};
|
||||
}, [editor]);
|
||||
|
||||
return headings;
|
||||
}
|
||||
Reference in new issue
Block a user