如何用 generateLinkForSelection 与 onLinkOpen 实现 Excalidraw 嵌入的元素级深链【免费下载链接】excalidrawVirtual whiteboard for sketching hand-drawn like diagrams项目地址: https://gitcode.com/GitHub_Trending/ex/excalidraw当你在自己的应用里嵌入了 Excalidraw 白板经常会遇到这类需求把一张画布中某个具体元素或一组元素的链接分享给别人对方打开后能直接定位到这个元素而不是落在画布空白处。Excalidraw 通过两个 props 支持这件事generateLinkForSelection让宿主应用接管根据选中元素生成链接的逻辑onLinkOpen让宿主应用在用户点击画布内链接时接管跳转行为。这两个能力在 props 文档 中有定义配套的生成与解析逻辑可以参见 elementLink.ts 与 actionElementLink.ts。机制元素链接是如何工作的Excalidraw 内置的元素链接约定是链接 当前页面 URL 加上查询参数?elementid参数名常量ELEMENT_LINK_KEY的值为element见 constants.ts。默认实现defaultGetElementLinkFromSelection就是照这个约定拼 URL// packages/element/src/elementLink.ts export const defaultGetElementLinkFromSelection (id, type) { const url window.location.href; try { const link new URL(url); link.searchParams.set(ELEMENT_LINK_KEY, id); // ELEMENT_LINK_KEY element return normalizeLink(link.toString()); } catch (error) { console.error(error); } return normalizeLink(url); };链接的另一半是打开后自动定位。当场景加载完成后如果window.location.href是一个元素链接Excalidraw 会解析出 id 并把视口直接对准它无动画、缩放适配// packages/excalidraw/components/App.tsx场景恢复末尾 if (isElementLink(this.ownerWindow.location.href)) { this.viewport.setViewport({ target: this.ownerWindow.location.href, fit: scale-down, animation: false, }); }setViewport解析链接的流程在 App.viewport.ts先用isElementLink(url)判断是否为元素链接要求 URL 带element参数且host window.location.host再用parseElementLinkFromURL取出 idid 可以是元素 id也可以是 group id会解析到组内所有元素。如果链接里的 id 在场景中不存在视口不变化并弹出elementLink.notFound的 toast 提示——这是判断深链是否生效的可见信号之一。id的取值规则见getLinkIdAndTypeFromSelection选中 1 个元素时id为该元素的idtype为element选中多个元素时要求它们属于同一个组id为 group idtype为group多个未分组的元素无法生成链接canCreateLinkFromElements返回false。步骤一传入 generateLinkForSelection 自定义链接格式generateLinkForSelection的签名是(id: string, type: element | group) string。官方文档明确说明这个 prop 用于替换默认的链接生成函数让宿主应用接管元素链接的创建链接可以用于导航到特定元素或分组如果宿主应用为元素链接 id 选择了不同的 key那么宿主应用也应负责在onLinkOpen中处理该链接的解析与跳转。Excalidraw generateLinkForSelection{(id, type) { const url new URL(window.location.href); // 保留默认的 element 参数另加自己的业务参数 url.searchParams.set(element, id); url.searchParams.set(focus, type group ? group : element); return url.toString(); }} /使用上面这个回调后生成形如https://your.app.com/board?elementidfocuselement的链接打开后依然命中 Excalidraw 内置的自动定位逻辑isElementLink只检查element参数与 host不排斥额外参数。如果换成自己独立的参数名例如只带?focusid内置逻辑就识别不了你需要自己在打开链接时通过excalidrawAPI的setViewport定位到目标元素并像后文onLinkOpen示例那样处理点击跳转。不传该 prop 时Copy element link复制元素链接等动作走默认实现defaultGetElementLinkFromSelection见 actionElementLink.ts。生成结果会经过normalizeLink归一化ElementLinkDialog.tsx 中同样如此。步骤二传入 onLinkOpen 接管链接点击用户点击画布元素上带链接的 handle 时onLinkOpen被触发签名为(element: ExcalidrawElement, event: CustomEvent{ nativeEvent: MouseEvent }) void。文档要求如果你要自己处理跳转例如使用自己的 router 处理站内链接必须调用event.preventDefault()否则 Excalidraw 会继续执行默认打开行为站内链接当前窗口打开、外链新窗口打开见 App.tsx。props 文档给出的示例React Router 场景内部链接走应用路由、外部链接新开标签页const history useHistory(); // open internal links using the apps router, but opens external links in // a new tab/window const onLinkOpen: ExcalidrawProps[onLinkOpen] useCallback( (element, event) { const link element.link; const { nativeEvent } event.detail; const isNewTab nativeEvent.ctrlKey || nativeEvent.metaKey; const isNewWindow nativeEvent.shiftKey; const isInternalLink link.startsWith(/) || link.includes(window.location.origin); if (isInternalLink !isNewTab !isNewWindow) { history.push(link.replace(window.location.origin, )); // signal that were handling the redirect ourselves event.preventDefault(); } }, [history], );仓库自带的示例应用 ExampleApp.tsx 实现了同样的判断骨架并通过cloneElement(Excalidraw, { onLinkOpen, ... })把它传给组件。示例中拦截内部链接后仅调用event.preventDefault()并注释do a custom redirect, such as passing to react-router具体跳转逻辑需要你自己接上。验证从复制链接到打开定位的完整闭环按下面的路径可以逐步确认深链已经打通生成链接在嵌入的白板中选中一个元素或同一组内的多个元素执行 Copy element link / Link to element对应 actionElementLink.ts 中的copyElementLink与linkToElement两个 action。复制成功的反馈是 toasttoast.elementLinkCopiedLink to element 打开的对话框会把generateLinkForSelection的返回值预填进输入框ElementLinkDialog.tsx在这里可以直接目检链接是否符合你在步骤一中的自定义格式。打开链接把复制的 URL 放到新标签页打开。前提是该 URL 上的场景数据与生成时一致同一个画布 / 同一份initialData。加载完成后视口会自动平移到目标元素并缩放适配fit: scale-down。失败信号如果链接中的元素 id 或 group id 在当前场景中不存在元素被删除、场景不一致等视口不变画面会出现elementLink.notFound的 toastApp.viewport.ts。看到该提示即可判定链接有效但目标缺失。点击跳转把某个元素设为可点击链接后点击它确认onLinkOpen被触发内部链接且调用过event.preventDefault()时Excalidraw 不再自行打开该 URL由你的路由接管。另外两个实用细节悬停在带链接的元素上时Excalidraw 会把 tooltip 显示为 go to elementlabels.link.goToElement而不是完整 URL——这是元素链接与普通超链接的可见区别Hyperlink.tsx。如果宿主应用自己做了 SPA 路由、需要程序化解析这类链接包出口导出了isElementLink并可以从 elementLink.ts 参考parseElementLinkFromURL的写法读取element查询参数。限制与边界多个元素只有在同属一个组时才能生成链接跨组多选无法生成copyElementLink的predicate基于canCreateLinkFromElements判断未满足时动作不出现 / 不生效。默认的元素链接判定要求链接的 host 与window.location.host相同跨 origin 的元素链接不会被isElementLink识别需要由宿主应用自行处理解析与定位。自定义generateLinkForSelection后若参数名偏离默认的elementkey文档明确提醒解析与跳转的责任转移到宿主应用通常需要配合onLinkOpen和excalidrawAPI.setViewport完成定位内置的打开即定位不会再帮你做。【免费下载链接】excalidrawVirtual whiteboard for sketching hand-drawn like diagrams项目地址: https://gitcode.com/GitHub_Trending/ex/excalidraw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考