ai-portal-blocknote-editor
v0.0.27
Published
一个基于 BlockNote(React)在 Vue 3 中封装的富文本/知识块编辑器组件,内置中文词典、AI 助手按钮、Markdown 粘贴与按块插入、标题扩展(支持 `agentId`)等能力。
Downloads
79
Readme
BlockNoteEditor 使用说明
一个基于 BlockNote(React)在 Vue 3 中封装的富文本/知识块编辑器组件,内置中文词典、AI 助手按钮、Markdown 粘贴与按块插入、标题扩展(支持 agentId)等能力。
安装与引入
npm install [email protected]
- 按需使用(单文件组件内局部注册):
```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。
基本用法
<template>
<BlockNoteEditor
ref="editorRef"
:default-content="content"
:placeholder="'请输入内容...'"
:read-only="false"
theme="light"
@content-change="onContentChange"
@editor-ready="onReady"
@editor-error="onError"
@handle-ai-assistant="onAiAssistant"
/>
</template>
<script setup lang="ts">
import { ref } from "vue";
const editorRef = ref<any>();
const content = ref<any[]>([]);
const onContentChange = (val: any[]) => {
content.value = val;
};
const onReady = (editor: any) => {
// 可使用 editor 原生能力
};
const onError = (err: any) => {
console.error("Editor error:", err);
};
const onAiAssistant = (text: string, type: string, agentId?: string) => {
// text: 选中文本;type: 操作类型(rewrite | continue | summarize | ask);agentId: 最近标题上的 agentId
};
// 示例:外部调用暴露方法
const insertDemo = async () => {
editorRef.value?.insertContent("Hello **World**");
};
</script>Props
defaultContent?: any[]:初始内容(BlockNote 块结构数组,参考 https://www.blocknotejs.org/docs)readOnly?: boolean:是否只读(当前实现以编辑态为主)。placeholder?: string:无内容时的占位文本。theme?: 'light' | 'dark'| any:主题。参考 https://www.blocknotejs.org/docs/react/styling-theming/themes
说明:组件在设置内容时会进行最小校验与深拷贝,尽量保持原始结构不变。
事件(Emits)
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。
暴露方法(通过 ref 获取)
const api = editorRef.value;getEditor(): any:获取底层 BlockNote 编辑器实例。getContent(): any[]:获取当前文档内容(顶层块)。setContent(content: any[]):替换为指定内容(内部做了验证与深拷贝)。focus(): void:聚焦编辑器。clear(): void:清空`。pasteMarkdown(markdown: string, isEmpty: boolean): Promise<void>:将 Markdown 解析为块并插入/替换。pasteMarkdownWithAgentId(contentList: { contentText: string; agentId?: string; title?: string }[], isEmpty: boolean): Promise<void>:解析 Markdown 并为匹配到标题文本的heading块写入agentId,再插入/替换。getSelectedText(): string:返回当前 ProseMirror 选区的纯文本(无选区返回空字符串)。insertContent(text: string): Promise<void>:内联插入文本,支持**加粗**解析;自动添加黄色背景高亮,并在插入位置后插入操作按钮块(接受/取消)。insertContentReplaceSelected(text: string, type: string): Promise<void>:当type === 'rewrite'且存在选区时,替换选中文本,支持**加粗**,并添加高亮与按钮块;否则退化为按块或内联插入。acceptInsertion(targetHighlightId?: string): void:接受插入,移除加粗与背景并删除对应的按钮块;可传入highlightId指定目标。cancelInsertion(targetHighlightId?: string): void:取消插入,撤回为原文本并移除按钮块;可传入highlightId指定目标。getInsertState(): { ... }:返回最近一次插入的状态对象。hasPendingInsertions(): boolean:是否存在未确认(接受/取消)的插入。
备注:同时支持并发多处插入,内部通过
highlightId(如highlight-<timestamp>-<rand>)区分;acceptInsertion/cancelInsertion支持入参精确控制。
AI 助手菜单说明
工具栏包含自定义按钮“AI 助手”,点击后出现下拉菜单:
rewrite:改写(当前实现触发事件,外部接入 AI 后可回填到编辑器,可配合insertContentReplaceSelected)。continue:续写(外部实现)。summarize:总结(外部实现)。ask:问 AI(外部实现)。
组件会根据当前选区与最近标题(支持 agentId 的扩展 heading)回传 agentId,便于外部路由到具体 Agent 服务。
常用示例
- 将 AI 结果“以块为主”插入:
// 优先尝试作为块(列表/标题/代码等)插入,失败再内联
await editorRef.value?.insertContent("## 小节\n- A\n- B");- 覆盖选中文本并高亮(改写场景):
// 假设用户选中了一段文字,AI 返回富文本标记:
await editorRef.value?.insertContentReplaceSelected("优化后的 **文本**", "rewrite");
// 用户可点击“接受/取消”按钮块,或调用:
editorRef.value?.acceptInsertion(); // 或传入精确的 highlightId
editorRef.value?.cancelInsertion();- 粘贴 Markdown 列表(空文档直接替换,非空则追加):
await editorRef.value?.pasteMarkdown("# 标题\n\n内容", /* isEmpty */ false);- 获取/设置内容:
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
