ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

BlockNote 链接工具栏(Link Toolbar)自定义按钮实战:为悬停链接工具栏添加 “Open Alert“ 按钮

BlockNote 链接工具栏(Link Toolbar)自定义按钮实战:为悬停链接工具栏添加 “Open Alert“ 按钮 BlockNote 链接工具栏Link Toolbar自定义按钮实战为悬停链接工具栏添加 Open Alert 按钮【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址: https://gitcode.com/gh_mirrors/bl/BlockNote本指南以 BlockNote 官方示例 16-link-toolbar-buttons 为核心系统讲解如何为 BlockNote 编辑器的 Link Toolbar鼠标悬停链接或光标落在链接内时弹出的浮层工具栏添加自定义按钮。读完本文你将掌握LinkToolbar/LinkToolbarController/LinkToolbarProps的完整用法、默认三个按钮编辑、打开、删除的实现原理以及如何基于useComponentsContext编写自己的链接操作按钮并将其无缝嵌入默认工具栏。一、示例背景什么是 Link Toolbar在 BlockNote基于 ProseMirror 与 Tiptap 构建的块级富文本编辑器中当用户将鼠标悬停在文档中的某个超链接上或者将文本光标移动到链接内部时编辑器会自动弹出一个紧凑的浮层工具栏用于对该链接进行快速操作。这个浮层就是Link Toolbar。示例 README 的目标非常明确在默认的 Link Toolbar 中新增一个按钮点击后弹出浏览器alert展示当前链接的 URLIn this example, we add a button to the Link Toolbar which opens a browser alert.Try it out:Hover the link open the Link Toolbar, and click the new Open Alert button!与格式化工具栏Formatting Toolbar、侧边菜单Side Menu一样Link Toolbar 是 BlockNote 提供的一套可深度定制的 UI 组件体系。本示例位于 examples/03-ui-components/16-link-toolbar-buttons/与同目录下的04-side-menu-buttons、06-suggestion-menus-slash-menu-items等示例共同构成 UI 组件定制系列。二、完整示例代码解析该示例由两个核心文件组成下文逐一拆解。1. App.tsx装配自定义 Link ToolbarApp.tsx 完整代码如下import blocknote/core/fonts/inter.css; import { BlockNoteView } from blocknote/mantine; import blocknote/mantine/style.css; import { DeleteLinkButton, EditLinkButton, LinkToolbar, LinkToolbarController, LinkToolbarProps, OpenLinkButton, useCreateBlockNote, } from blocknote/react; import { AlertButton } from ./AlertButton; const CustomLinkToolbar (props: LinkToolbarProps) ( LinkToolbar {...props} EditLinkButton url{props.url} text{props.text} range{props.range} setToolbarOpen{props.setToolbarOpen} setToolbarPositionFrozen{props.setToolbarPositionFrozen} / OpenLinkButton url{props.url} / DeleteLinkButton range{props.range} setToolbarOpen{props.setToolbarOpen} / {/* Extra button to open alert. */} AlertButton {...props} / /LinkToolbar ); export default function App() { // Creates a new editor instance. const editor useCreateBlockNote({ initialContent: [ { type: paragraph, content: Welcome to this demo!, }, { type: paragraph, content: Hover the link below to see the modified Link Toolbar, }, { type: paragraph, content: [ { type: link, href: https://www.blocknotejs.org/, content: [ { type: text, text: Home Page, styles: {}, }, ], }, ], }, ], }); // Renders the editor instance. return ( BlockNoteView editor{editor} linkToolbar{false} LinkToolbarController linkToolbar{CustomLinkToolbar} / /BlockNoteView ); }要点拆解关闭内置 Link ToolbarBlockNoteView editor{editor} linkToolbar{false}通过将linkToolbar属性置为false禁用BlockNoteView内部自动挂载的默认 Link Toolbar避免与自定义控制器重复渲染。挂载自定义控制器LinkToolbarController linkToolbar{CustomLinkToolbar} /作为BlockNoteView的子节点传入。LinkToolbarController负责监听光标位置与鼠标悬停计算链接范围并决定工具栏的显示/隐藏linkToolbar属性接收一个接收LinkToolbarProps并返回 JSX 的组件用于完全替换默认工具栏内容。保留默认按钮CustomLinkToolbar内部显式渲染了EditLinkButton、OpenLinkButton、DeleteLinkButton三个默认按钮——因为LinkToolbar组件在传入children时会用children完全替代默认按钮组见下文源码剖析所以想保留原有功能就必须手动补齐。追加自定义按钮AlertButton {...props} /将整套LinkToolbarProps透传给自定义按钮使其能够访问当前链接的 URL、文本与选区范围。初始化内容含链接initialContent中通过内联内容{ type: link, href: https://www.blocknotejs.org/, content: [...] }预置了一个链接方便演示悬停效果。2. AlertButton.tsx自定义按钮实现AlertButton.tsx 完整代码如下import { LinkToolbarProps, useComponentsContext } from blocknote/react; // Custom Link Toolbar button to open a browser alert. export function AlertButton(props: LinkToolbarProps) { const Components useComponentsContext()!; return ( Components.LinkToolbar.Button mainTooltip{Open Alert with URL} onClick{() window.alert(Link URL: ${props.url})} Open Alert /Components.LinkToolbar.Button ); }实现原理useComponentsContext()这是 BlockNote React 包提供的重要 Hook返回当前 UI 组件库mantine/shadcn/ariakit 等注册的组件集合。Components.LinkToolbar.Button是 Link Toolbar 中标准按钮的抽象组件由底层 UI 库具体实现从而保证自定义按钮与默认按钮在外观、无障碍语义tooltip、label上保持一致。mainTooltip设置按钮的悬停提示文本此示例为 Open Alert with URL。onClick点击后读取props.url当前链接地址并弹出浏览器原生alert对话框。props.url的来源由LinkToolbarController在检测到链接时注入是链接 mark 的href属性值。三、核心 API 详解LinkToolbarProps、LinkToolbar 与 LinkToolbarController三个导出组件/类型均从blocknote/react导出其声明位置在 packages/react/src/index.tsexport * from ./components/LinkToolbar/DefaultButtons/DeleteLinkButton.js; export * from ./components/LinkToolbar/DefaultButtons/EditLinkButton.js; export * from ./components/LinkToolbar/DefaultButtons/OpenLinkButton.js; export * from ./components/LinkToolbar/EditLinkMenuItems.js; export * from ./components/LinkToolbar/LinkToolbar.js; export * from ./components/LinkToolbar/LinkToolbarController.js; export * from ./components/LinkToolbar/LinkToolbarProps.js;1. LinkToolbarProps工具栏的输入数据契约LinkToolbarProps.ts 定义了所有 Link Toolbar 组件共享的 propsimport { Range } from tiptap/core; import { ReactNode } from react; export type LinkToolbarProps { url: string; text: string; range: Range; setToolbarOpen?: (open: boolean) void; setToolbarPositionFrozen?: (frozen: boolean) void; children?: ReactNode; };属性类型含义urlstring当前链接的 URLmark 的href自定义按钮最常使用textstring链接的显示文本内容rangeRange来自tiptap/core链接在文档中的选区范围{ from, to }删除/编辑链接时使用setToolbarOpen(open: boolean) void控制工具栏开合例如删除链接后调用setToolbarOpen(false)关闭浮层setToolbarPositionFrozen(frozen: boolean) void冻结/解冻工具栏位置编辑链接的弹层打开时调用以阻止浮层跟随光标跳动childrenReactNode子内容LinkToolbar用它替换默认按钮组2. LinkToolbar默认工具栏容器LinkToolbar.tsx 的默认行为是当没有传入children时渲染三个默认按钮EditLinkButton、OpenLinkButton、DeleteLinkButton当传入children时children完全替代默认按钮组因此示例必须手动保留默认按钮export const LinkToolbar (props: LinkToolbarProps) { const Components useComponentsContext()!; return ( Components.LinkToolbar.Root className{bn-toolbar bn-link-toolbar} {props.children || ( EditLinkButton ... / OpenLinkButton url{props.url} / DeleteLinkButton ... / / )} /Components.LinkToolbar.Root ); };源码注释同时提示了扩展方式默认按钮位于DefaultButtons目录若要自定义选择器/按钮可使用 mantine 共享目录components/mantine-shared/Toolbar中的ToolbarSelect与ToolbarButton组件。CSS 类名bn-toolbar bn-link-toolbar可通过全局样式覆盖定制外观。3. LinkToolbarController浮层的“大脑”LinkToolbarController.tsx 承担链接检测与浮层管理PropslinkToolbar自定义工具栏组件、floatingUIOptions基于 Floating UI 的定位选项、portalElement覆盖浮层挂载的 DOM 节点。链接检测双通道文本光标订阅editor.onChange与editor.onSelectionChange调用linkToolbar.getLinkAtSelection()见 packages/core/src/extensions/LinkToolbar/LinkToolbar.ts光标落在链接内即展示鼠标悬停为编辑器 DOM 监听mouseover调用getLinkAtElement(event.target)同文件 L57-L62从悬停元素向上查找a节点文本光标命中的链接优先级高于鼠标悬停的链接。核心工具方法来自 core 包LinkToolbarExtensiongetLinkAtSelection()、getLinkAtElement()、getLinkElementAtPos()沿 DOM 父链向上寻找nodeName A的锚点元素、editLink()、deleteLink()。定位与交互细节使用 Floating UI 的placement: top-start、offset(10)、flip()中间件鼠标悬停展开/收起延迟各 250ms并使用safePolygon()防止指针移出时浮层过早消失浮层zIndex: 50。非编辑态if (!editor.isEditable) return null;只读模式下不渲染链接工具栏。位置冻结编辑链接弹层打开时setToolbarPositionFrozen(true)冻结浮层位置防止光标变化导致浮层跳动。4. 默认按钮源码剖析三个默认按钮分别位于 packages/react/src/components/LinkToolbar/DefaultButtons/EditLinkButton.tsx外层是Components.Generic.Popover表单弹层内部渲染EditLinkMenuItems编辑 URL 与显示文本的表单。打开弹层时通过onOpenChange{props.setToolbarPositionFrozen}冻结浮层位置tooltip 文案取自 i18n 字典dict.link_toolbar.edit.tooltip。OpenLinkButton.tsx点击后window.open(sanitizeUrl(props.url, window.location.href), _blank)新标签页打开链接。注意它先经sanitizeUrl清洗 URL 再打开可参考安全实践。DeleteLinkButton.tsx通过useExtension(LinkToolbarExtension)获取deleteLink点击时调用deleteLink(props.range.from)从range.from位置删除链接随后props.setToolbarOpen?.(false)关闭工具栏。这些默认按钮本身也是自定义按钮的绝佳范例自定义AlertButton与它们共用同一个Components.LinkToolbar.Button基座因此样式与行为天然一致。四、运行与验证示例是标准的 Vite React 应用工程配置见 package.json依赖blocknote/core、blocknote/mantine、blocknote/react示例版本号0.12.4仓库内均以latest引入实际解析以 pnpm workspace 为准。# 安装依赖仓库根目录pnpm workspace pnpm install # 启动示例 cd examples/03-ui-components/16-link-toolbar-buttons pnpm start # 等价于 pnpm dev即 vite 开发服务器也可以直接使用pnpm dev生产构建用pnpm build:prod先tsc类型检查再vite buildpnpm preview预览构建产物。验证步骤页面加载后文档中出现 Home Page 链接href 指向https://www.blocknotejs.org/将鼠标悬停在该链接上或把光标移入链接文本内部Link Toolbar 浮层出现包含四个按钮Edit、Open、Delete 与新增的Open Alert点击Open Alert浏览器弹出alert对话框内容为Link URL: https://www.blocknotejs.org/。五、进阶扩展建议添加多个自定义按钮在CustomLinkToolbar中按需追加多个类似AlertButton的组件即可每个组件通过props访问url/text/range可实现复制链接、发送到某处、打开二维码弹层等业务能力。改造现有按钮而非新增直接替换OpenLinkButton为自定义实现如站内路由跳转代替window.open并保留EditLinkButton、DeleteLinkButton。在只读场景的取舍LinkToolbarController在editor.isEditable false时返回null即只读视图不会显示 Link Toolbar若需在只读文档中展示链接浮层需自行处理。i18n 与样式默认按钮的 tooltip 文案取自字典如dict.link_toolbar.open.tooltip自定义按钮可沿用useDictionary或直接写死字符串样式可通过bn-toolbar bn-link-toolbar类名覆盖。对比同系列示例本示例与 04-side-menu-buttons侧边菜单按钮、03-formatting-toolbar-block-type-items格式化工具栏结构一致——都是关闭默认组件 通过 Controller 注入自定义组件 用useComponentsContext获取底层按钮基座的模式掌握其一即可举一反三。六、小结通过本示例我们可以总结出 BlockNote Link Toolbar 自定义的完整链路BlockNoteView上设置linkToolbar{false}关闭默认浮层传入LinkToolbarController linkToolbar{CustomLinkToolbar} /接管链接浮层自定义组件接收LinkToolbarProps含url、text、range及开合控制回调组合默认按钮与自定义按钮自定义按钮基于useComponentsContext()返回的Components.LinkToolbar.Button渲染与默认按钮外观统一。从底层看链接的定位、编辑、删除能力由 core 包中的LinkToolbarExtensionpackages/core/src/extensions/LinkToolbar/LinkToolbar.ts提供React 层的LinkToolbarController只是其 UI 呈现理解这一分层后无论是加按钮、换交互还是做安全增强如 URL 清洗都能在正确的位置下手。若需回顾编辑器的基本初始化方式可参考仓库文档 editor-setup。【免费下载链接】BlockNoteA React Rich Text Editor thats block-based (Notion style) and extensible. Built on top of Prosemirror and Tiptap.项目地址: https://gitcode.com/gh_mirrors/bl/BlockNote创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表