如何启用 tldraw 深度链接通过 URL 分享画布位置与形状
【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw
在基于 tldraw SDK 的 React 应用中,如果你需要把"当前看到的内容"分享出去——某个形状、某个视口区域或某个页面——tldraw 的深链接(Deep links)功能可以把编辑器状态序列化为 URL 安全的字符串,别人打开链接时就能落到相同的位置。前提是你已经在项目中安装了tldraw包并渲染了<Tldraw>组件;启用后,URL 上会出现d查询参数,画布平移缩放时它会自动保持最新,打开该链接即可恢复相同的页面与视口。
用deepLinks选项一行启用
最简单的启用方式是在<Tldraw>组件的optionsprop 里传入deepLinks: true:
import { Tldraw } from 'tldraw' import 'tldraw/tldraw.css' export default function App() { return ( <div style={{ position: 'fixed', inset: 0 }}> <Tldraw persistenceKey="example" options={{ deepLinks: true }} /> </div> ) }启用之后,组件在编辑器初始化、首次渲染之前会检查window.location中名为d的查询参数;如果找到,就把它的值解析为深链接并导航过去。此后每次相机或页面变化,约 500 毫秒后 URL 上的d参数会被更新为最新状态。官方示例 DeepLinksExample 就是这个最简用法。
注意:<TldrawEditor>上也存在一个deepLinksprop,但源码中标注了@deprecated Use options.deepLinks instead,新代码应使用options.deepLinks。
验证效果:URL 上的d参数
保存代码并运行开发环境后,可以按文档示例的方式验证:
- 在画布上创建一个形状,然后平移或缩放画布;
- 观察浏览器地址栏,
d搜索参数会随你移动而更新,形如?d=v1234.-234.3.21; - 复制这个 URL,在新标签页打开,应回到相同的页面与视口位置。
官方示例的说明原文(见 示例 README)即以此作为该功能可用与否的判断方式。
三种深链接类型与编码格式
一个TLDeepLink是三种类型之一,编码为带单字符前缀的紧凑字符串(前缀对应关系见 deep-links 文档):
| Type | Purpose | Encoded prefix |
|---|---|---|
shapes | 链接到特定形状,缩放至适配它们 | s |
viewport | 链接到一个包围盒视图,可附带页面 | v |
page | 链接到特定页面,缩放至适配其内容 | p |
具体的编码规则:
- 形状链接(
s)以点号分隔形状 ID:s<id1>.<id2>.<id3> - 视口链接(
v)编码取整后的包围盒坐标:v<x>.<y>.<w>.<h>,可附带页面 ID - 页面链接(
p)编码一个页面 ID:p<pageId>
所有 ID 都会做 URL 编码以处理特殊字符(点号本身会被编码为%2E,因为点号用作分隔符,见 deepLinks.ts)。
导航时的行为有明确的回退逻辑:
- 导航到
shapes深链接时,编辑器会切换到包含最多这些形状的页面并缩放适配; viewport深链接把相机设置到指定包围盒;- 如果参数缺失、值无效,或者对应形状/页面已不存在,编辑器改为缩放适配当前页面内容。
定制选项:参数名、防抖与自定义 URL
把deepLinks: true换成一个 TLDeepLinkOptions 对象即可定制行为。<Tldraw>组件的options.deepLinks与Editor#registerDeepLinkListener方法接受相同的字段:
| Option | Description |
|---|---|
param | 查询参数名,默认'd' |
debounceMs | 更新 URL 前的等待时间(毫秒),默认500 |
getTarget | 返回要编码的 TLDeepLink,默认是当前页面与视口 |
getUrl | 返回要添加参数的基础 URL;提供它就必须同时提供onChange |
onChange | URL 更新时回调,默认调用window.history.replaceState |
文档给出的两个可选分支示例:
// 换用 `view` 作为参数名,并用前端路由替换 URL(getUrl 与 onChange 必须成对提供) <Tldraw options={{ deepLinks: { param: 'view', getUrl: () => window.location.href, onChange: (url) => router.replace(url.toString()), }, }} />// 只链接当前页面,并把防抖改为 100ms <Tldraw options={{ deepLinks: { param: 'page', getTarget(editor) { return { type: 'page', pageId: editor.getCurrentPageId() } }, onChange(url) { console.log('the new search params are', url.searchParams) }, debounceMs: 100, }, }} />第二种写法适合不想让 tldraw 直接改window.location、而只把新参数打出来或交给自己路由处理的场景。
手动模式:不依赖deepLinks选项时的三个方法
如果你希望完全自己控制(例如不想在 URL 里放搜索参数,或想在按钮点击时才生成链接),可以直接使用编辑器方法。以下代码示例取自 deep-links 文档:
createDeepLink:生成分享 URL
// Create a link to the current viewport const url = editor.createDeepLink() navigator.clipboard.writeText(url.toString())也可以指定目标,比如链接到当前选中的形状:
// Link to currently selected shapes const url = editor.createDeepLink({ to: { type: 'shapes', shapeIds: editor.getSelectedShapeIds() }, })不传to时默认编码当前视口(包围盒与页面);第二个参数param可覆盖默认的d参数名。
navigateToDeepLink:导航到链接位置
import { TLShapeId } from 'tldraw' // Navigate using the current URL's query parameter editor.navigateToDeepLink() // Navigate to a specific URL editor.navigateToDeepLink({ url: 'https://example.com?d=v100.100.200.200' }) // Navigate directly to shapes editor.navigateToDeepLink({ type: 'shapes', shapeIds: ['shape:abc' as TLShapeId, 'shape:xyz' as TLShapeId], })示例中的https://example.com?d=v100.100.200.200是文档示例,v100.100.200.200表示 x=100、y=100、w=200、h=200 的视口包围盒,不是固定预期值。
registerDeepLinkListener:自动同步 URL
// Use default behavior (replaces the current URL without adding history entries) const unlisten = editor.registerDeepLinkListener() // Custom change handler with longer debounce const unlisten = editor.registerDeepLinkListener({ onChange(url) { window.history.replaceState({}, document.title, url.toString()) }, debounceMs: 1000, }) // Clean up when done unlisten()<Tldraw>组件的deepLinks选项内部调用的就是这个方法。在自定义组件里使用它时,记得在useEffect的清理函数中调用返回的unlisten()(示例见 deep-links 示例 README 的 "Listening for deep link changes" 一节)。
另外两个无编辑器依赖的工具函数适合纯字符串场景:createDeepLinkString 把TLDeepLink描述对象编码为字符串,parseDeepLinkString做反向解析。文档给出的编码示例(文档示例,用于说明格式):
createDeepLinkString({ type: 'page', pageId: 'page:abc123' }) // => 'pabc123' createDeepLinkString({ type: 'shapes', shapeIds: ['shape:foo', 'shape:bar'] }) // => 'sfoo.bar'解析失败(未知前缀、坐标不是有限数值等)会抛出Error('Invalid deep link string');navigateToDeepLink捕获该错误后回退到缩放适配页面内容,并在控制台输出警告。
限制与回退行为小结
- 默认查询参数是
d;如果应用自身路由已经在用d参数,用param选项改名。 - 提供
getUrl时必须同时提供onChange,否则registerDeepLinkListener会直接抛出错误。 - 链接指向的形状或页面在文档中被删除后,打开链接不会报错,而是回退到缩放适配页面内容——这是文档明确的行为,不是异常。
- URL 更新默认走
window.history.replaceState,不会产生额外的浏览器历史条目,但也不会自动写入前端路由;需要路由接管时按前文的onChange分支处理。
深入细节可以继续阅读 deep-links 官方文档 与 Deep links 示例。
【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考