一个基于 BlockNote(React)在 Vue 3 中封装的富文本/知识块编辑器组件,内置中文词典、AI 助手按钮、Markdown 粘贴与按块插入、标题扩展(支持 `agentId`)等能力。
npm install ai-portal-blocknote-editor一个基于 BlockNote(React)在 Vue 3 中封装的富文本/知识块编辑器组件,内置中文词典、AI 助手按钮、Markdown 粘贴与按块插入、标题扩展(支持 agentId)等能力。
```ts
npm install ai-portal-blocknote-editor@0.0.11
- 按需使用(单文件组件内局部注册):
`ts``
// 在 SFC 中
import { BlockNoteEditor } from "ai-portal-blocknote-editor";
import "ai-portal-blocknote-editor/pack_dist/style.css";
> 依赖(peerDependencies):vue@^3.3.8、react@^18、react-dom@^18、@blocknote/*@^0.36.0、less。
`vue
:default-content="content"
:placeholder="'请输入内容...'"
:read-only="false"
theme="light"
@content-change="onContentChange"
@editor-ready="onReady"
@editor-error="onError"
@handle-ai-assistant="onAiAssistant"
/>
`
- defaultContent?: any[]:初始内容(BlockNote 块结构数组,参考 readOnly?: boolean
- :是否只读(当前实现以编辑态为主)。placeholder?: string
- :无内容时的占位文本。theme?: 'light' | 'dark'
- | any:主题。参考
说明:组件在设置内容时会进行最小校验与深拷贝,尽量保持原始结构不变。
- content-change(content: any[]):内容变化时触发(顶层块数组)。editor-ready(editor: any)
- :编辑器创建完成;可保存实例使用其原生 API。editor-error(error: any)
- :编辑器渲染或运行出错。handle-ai-assistant(text: string, type: string, agentId?: string)
- :点击工具栏中的“AI 助手”菜单项触发。text
- :当前选区的纯文本内容。type
- :操作类型:rewrite | continue | summarize | ask。agentId
- :根据选中块向上回溯最近的标题块(扩展的 heading)上的 agentId。
`ts`
const api = editorRef.value;
- getEditor(): any:获取底层 BlockNote 编辑器实例。getContent(): any[]
- :获取当前文档内容(顶层块)。setContent(content: any[])
- :替换为指定内容(内部做了验证与深拷贝)。focus(): void
- :聚焦编辑器。clear(): void
- :清空。
- pasteMarkdown(markdown: string, isEmpty: boolean): Promise:将 Markdown 解析为块并插入/替换。
- pasteMarkdownWithAgentId(contentList: { contentText: string; agentId?: string; title?: string }[], isEmpty: boolean): Promise:解析 Markdown 并为匹配到标题文本的 heading 块写入 agentId,再插入/替换。
- getSelectedText(): string:返回当前 ProseMirror 选区的纯文本(无选区返回空字符串)。
- insertContent(text: string): Promise:内联插入文本,支持 加粗 解析;自动添加黄色背景高亮,并在插入位置后插入操作按钮块(接受/取消)。
- insertContentReplaceSelected(text: string, type: string): Promise:当 type === 'rewrite' 且存在选区时,替换选中文本,支持 加粗,并添加高亮与按钮块;否则退化为按块或内联插入。
- acceptInsertion(targetHighlightId?: string): void:接受插入,移除加粗与背景并删除对应的按钮块;可传入 highlightId 指定目标。
- cancelInsertion(targetHighlightId?: string): void:取消插入,撤回为原文本并移除按钮块;可传入 highlightId 指定目标。
- getInsertState(): { ... }:返回最近一次插入的状态对象。
- hasPendingInsertions(): boolean:是否存在未确认(接受/取消)的插入。
> 备注:同时支持并发多处插入,内部通过 highlightId(如 highlight-)区分;acceptInsertion/cancelInsertion 支持入参精确控制。
工具栏包含自定义按钮“AI 助手”,点击后出现下拉菜单:
- rewrite:改写(当前实现触发事件,外部接入 AI 后可回填到编辑器,可配合 insertContentReplaceSelected)。
- continue:续写(外部实现)。
- summarize:总结(外部实现)。
- ask:问 AI(外部实现)。
组件会根据当前选区与最近标题(支持 agentId 的扩展 heading)回传 agentId,便于外部路由到具体 Agent 服务。
- 将 AI 结果“以块为主”插入:
``ts`
// 优先尝试作为块(列表/标题/代码等)插入,失败再内联
await editorRef.value?.insertContent("## 小节\n- A\n- B");
- 覆盖选中文本并高亮(改写场景):
`ts`
// 假设用户选中了一段文字,AI 返回富文本标记:
await editorRef.value?.insertContentReplaceSelected("优化后的 文本", "rewrite");
// 用户可点击“接受/取消”按钮块,或调用:
editorRef.value?.acceptInsertion(); // 或传入精确的 highlightId
editorRef.value?.cancelInsertion();
- 粘贴 Markdown 列表(空文档直接替换,非空则追加):
`ts`
await editorRef.value?.pasteMarkdown("# 标题\n\n内容", / isEmpty / false);
- 获取/设置内容:
`ts`
const data = editorRef.value?.getContent();
editorRef.value?.setContent(data ?? []);
- 组件围绕 BlockNote 的顶层块结构工作,尽量保持原始结构不变;设置内容前会做最小校验与深拷贝,避免只读/响应式引用问题。
- 内联插入会借助 ProseMirror 直接操作文档,并添加 textStyle 背景色标记;加粗通过 strong mark 实现。ExtendedHeading
- 自定义块:
- :保留原生 heading 类型与属性,额外支持 agentId(用于外部路由 AI Agent)。actionButtons
- :用于显示“接受/取消”按钮的块(自动插入/删除)。insertedText
- :内部用于展示插入文本及按钮的自定义块(目前主要走内联高亮与 actionButtons 方案)。
- 组件内已引入:
- @blocknote/core/fonts/inter.css@blocknote/mantine/style.css
- scoped less
- 工具栏位置与滚动在 中做了兼容处理。
- 若渲染失败,会在容器内展示简要报错卡片,同时触发 editor-error` 事件;请打开控制台查看详细报错。
- 请确保安装了所需的 peer 依赖,且 React 运行时与样式表可用。
MIT