ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Lightdash 前端首次引导上手导览(Onboarding Tour)开发实战:零依赖导览套件与确定性示例数据注入

Lightdash 前端首次引导上手导览(Onboarding Tour)开发实战:零依赖导览套件与确定性示例数据注入 Lightdash 前端首次引导上手导览Onboarding Tour开发实战零依赖导览套件与确定性示例数据注入【免费下载链接】lightdashAgentic BI. Analytics at the speed of code ⚡️项目地址: https://gitcode.com/GitHub_Trending/li/lightdash本文基于 Lightdash 仓库内add-onboarding-tour技能文档SKILL.md整理。Lightdash 是开源的 Agentic BI 平台其前端packages/frontend内置了一套零第三方依赖的首次运行引导first-run onboarding套件用于给任意页面快速接入「自动弹出导览 聚光灯高亮 示例数据」能力。读完本文你将掌握useGuidedTour、GuidedTour组件与useOnboardingMock三个核心构件的职责边界、完整接入五步法、内容目录的组织约定以及如何借助源码级的运行机制轮询目标、路由跳转、输入/点击推进、busy 状态接管写出高确定性、可复现的引导流程。一、这套套件的设计哲学套件全局共享内容按功能就近存放在packages/frontend中首次引导不是一个「每页各写一套」的散装实现而是一套集中式的零依赖工具包centralised kit。它的核心原则是三个可复用的构建块building blocks承担所有重活每个功能只需提供自己的步骤文案、锚点、示例数据可选。套件kit是全局的内容content是每个功能自己的与某功能强相关的步骤、文案、示例行、仅导览使用的视觉元素一律放在该功能旁的onboarding/目录中禁止塞进全局目录也禁止把步骤或 mock 数据内联到页面/表格组件里——组件只负责渲染。三个构建块的职责划分如下表构件路径职责useGuidedTouruseGuidedTour.tslocalStorage「已看过」标记、首次访问自动打开、手动重放。返回{ isOpen, startTour, closeTour }GuidedTourcomponents/common/GuidedTour聚光灯渲染压暗页面、高亮data-tour目标、锚定一张 Next/Back/Skip 卡片target: null时渲染居中说明卡useOnboardingMockuseOnboardingMock.ts一个 react-query 的select在开关打开期间把真实数据替换为确定性的 mock 行仓库内的**参考实现reference implementation**是 AI Copilot 的 ReviewsIssues页面共三处代码各司其职接线wiringAiReviewsSettingsPage.tsxmock 行渲染mock rowsAiAgentAdminReviewItemsTable.tsx内容contentAdmin/onboarding/在动手写自己的导览前官方建议先读这三处参考实现直接复刻它们是最快的路径。二、三个构建块背后的源码实现2.1useGuidedTour状态生命周期与「已看过」持久化源码位于 useGuidedTour.ts。其选项与返回值类型为type UseGuidedTourOptions { /** localStorage 中已看过标记的唯一 key约定ld.feature.tour.vn */ storageKey: string; /** 用户首次进入该功能时是否自动打开默认 true */ autoStartOnFirstVisit?: boolean; }; type UseGuidedTourResult { isOpen: boolean; // 导览浮层是否展示 startTour: () void; // 打开或重放导览 closeTour: () void; // 关闭并记录已看过 };实现要点从源码可以直接确认isOpen的初始值由autoStartOnFirstVisit !hasSeen(storageKey)决定hasSeen读取localStorage.getItem(key) 1startTour仅把isOpen置为true重放不重新读标记closeTour先写标记再关闭因此只要用户点过 Skip 或完成过导览下次进入不再自动弹出读写 localStorage 均包裹在try/catch中如隐私模式下写入被拒注释明确说明一个会重新弹出的导览好过一次崩溃。参考实现在 AiReviewsSettingsPage.tsx 中的用法const { isOpen: isTourOpen, startTour, closeTour } useGuidedTour({ storageKey: ld.aiReviews.tour.v2, autoStartOnFirstVisit: !isSidebarOpen, });这里有一个值得注意的细节页面通过 URL 参数reviewItemUuid等驱动侧边栏如果用户深链直达某条 review导览锚点在侧边栏背后的看板上此时不自动触发但 hook 只在挂载时读取一次autoStartOnFirstVisit且不写已看过标记所以用户下一次纯看板访问时导览仍会自动弹出。2.2GuidedTour组件聚光灯、卡片与目标解析GuidedTour组件位于 components/common/GuidedTour/GuidedTour.tsx配套 GuidedTour.module.css、卡片布局计算 cardLayout.ts 以及组件测试 GuidedTour.test.tsx。零依赖的聚光灯文档明确没有 joyride/driver/intro.js压暗效果是一层box-shadow: 0 0 0 9999px的阴影打底由组件内部dim样式完成高亮洞随步骤在控件之间滑动GLIDE_MS 600的过渡时间与 CSS 缓动一致。从源码常量看这套交互相当精细const SPOTLIGHT_PADDING 6; // 高亮环相对目标的外扩 const GLIDE_MS 600; // 光环在控件间滑行时间 const TARGET_ATTRIBUTE data-tour-active; // 打在当前目标上的属性 const FALLBACK_GRACE_MS 1500; // 目标消失后回退路径的等待 const TARGET_PATIENCE_MS 15000; // 目标从未出现时的最长等待 const CARD_RETURN_MS 4000; // beacon 孤悬多久后卡片回归 const MIN_INPUT_CHARS 3; // 键入步骤的最小字符数 const INPUT_SETTLE_MS 900; // 键入停顿多久判定完成步骤类型GuidedTourStep是接入的核心数据结构除文档提到的target、title、body之外源码还支持一批用于多页面导览和实操型步骤的高级字段字段类型含义targetstring \| null步骤到达时解析的 CSS 选择器null渲染居中说明卡title/bodystring/ReactNode卡片标题与正文正文可以是任意 ReactNode如内嵌示意图routestring?该步骤所在的页面路由到达时若提供onNavigate会先请求宿主跳转从而支持跨页导览interactiveboolean?实操步骤不加点击拦截层只保留压暗和高亮环让学习者真的在页面上操作advanceOnTargetClickboolean?目标被点击即进入下一步advanceOnTargetInputboolean?目标是文本输入框输入达到MIN_INPUT_CHARS个字符并停顿INPUT_SETTLE_MS后前进suggestionstring?键入步骤的推荐值卡片提供一个Use it按钮直接填入目标字段viastring[]?到达target的点击路径目标不在页面上时光环停在路径上最深的可见控件detour{ target, title }[]?某些配置下通往目标的绕行控件出现即把光环与标题移过去busystring?本步骤页面仍在工作的表面如流式回复、运行中的查询其存在期间步骤不结束卡片显示产品自身的状态文案目标解析useResolvedSelector每个步骤在到达时才解析自己的目标行数据可能晚渲染解析优先级为步骤的target在页面上 → 否则detour控件在场 → 否则等待从未见过目标时最长TARGET_PATIENCE_MS见过后消失则FALLBACK_GRACE_MS→ 超时后回退到via路径上最深的可见控件。这意味着不要在打开导览时过滤步骤否则会丢掉那些目标尚未渲染的步骤。延迟目标late-rendering targetsuseTargetRect逐帧采样目标元素并调用scrollIntoView居中滚动目标没出现时卡片居中显示出现后光环滑过去、卡片从 beacon 展开。组件还会给当前目标打上data-tour-active属性方便仅在 hover 时显示的控件在被高亮时自行现身。实操型交互interactive步骤不做点击拦截避免拖拽被 blocker 吞掉但在 document 捕获阶段吞掉按钮/链接/菜单项/输入框上的点击防止学习者误触破坏被观察的表面advanceOnTargetClick/advanceOnTargetInput步骤则通过轮询为目标挂监听目标点击后光环先收缩成 beaconCOLLAPSE_MS再滑向下一控件并展开卡片CARD_EXPAND_MS。收尾与保洁最后一步点击 Got it 会触发onFinish在onClose之前并关闭关闭时调用closeOpenDropdowns收起导览过程中被撑开的 Mantine 下拉菜单通过派发带data-mantine-stop-propagation标记的 Escape 键事件避免误关步骤刚打开的对话框。onStepChange(index, beacon)会把点击推进时的坐标传给宿主宿主若中途重挂载可用initialStepIndex与initialBeacon恢复到原步骤。2.3useOnboardingMock用 react-queryselect做确定性数据替换源码位于 useOnboardingMock.ts完整实现只有十余行export const useOnboardingMock T( mockData: T[], enabled: boolean, ): ((data: T[]) T[]) useCallback( (data: T[]) (enabled ? mockData : data), [mockData, enabled], );它返回一个 react-query 的select函数enabled为真比如导览正在运行时把真实数据整体替换为传入的mockData否则原样透传。前提是数据 hook 必须接受并把select转发给useQuery。参考实现 useAiAgentAdminReviewItems 正是这样做的export const useAiAgentAdminReviewItems ( args: { statuses?: AiAgentReviewItemStatus[] }, options?: { enabled?: boolean; select?: (...) ... }, ) { return useQuery({ ..., keepPreviousData: true, enabled: options?.enabled ?? true, select: options?.select }); };在 AiAgentAdminReviewItemsTable.tsx 中表格把 mock 行与开关组合起来const selectReviewItems useOnboardingMock(EXAMPLE_REVIEW_ITEMS, showOnboardingExamples); const { data: reviewItems [], isLoading } useAiAgentAdminReviewItems( { statuses: ACTIVE_REVIEW_ITEM_STATUSES }, { select: selectReviewItems }, );三、内容存放的固定目录结构所有功能专属内容放在功能目录旁的onboarding/文件夹且每次布局固定feature-dir/onboarding/ index.ts public surface仅重新导出供外部消费 steps.tsx TOUR_STEPS: GuidedTourStep[] 全部步骤文案 exampleData.ts EXAMPLE_*, isExample*() 仅当功能展示 mock 行时存在 Visual.tsx onboarding-only 视觉元素如示意图 .module.css功能代码统一从./onboarding导入。只在index.ts重新导出文件夹外部会被消费的内容仓库启用了ts-unused-exports校验未使用的导出会被视为错误。参考实现 onboarding/index.ts 只有两行export { EXAMPLE_REVIEW_ITEMS, isExampleReviewItem } from ./exampleData; export { REVIEWS_TOUR_STEPS } from ./steps;四、接入五步法Recipe步骤 1在功能页面接线导览状态const { isOpen, startTour, closeTour } useGuidedTour({ storageKey: ld.feature.tour.v1, });步骤 2在onboarding/steps.tsx定义步骤步骤是静态模块常量不需要useMemo。每个target是到达该步时才解析的 CSS 选择器null表示居中说明卡export const TOUR_STEPS: GuidedTourStep[] [ { target: [data-tourfeature-intro], title: …, body: … }, { target: [data-tourfeature-row], title: …, body: … }, { target: null, title: …, body: SomeDiagram / }, // 居中 ];页面从./onboarding导入TOUR_STEPS并传给GuidedTour。参考实现 steps.tsx 中的REVIEWS_TOUR_STEPS是一个六步导览开始位置 → 卡片含义 → 打开 PR → 跟进修复 → 构建验证 → 合并后的闭环最后一步target: null正文内嵌了ReviewsLoopDiagram示意图。步骤 3为元素添加data-tour锚点对表格行在行 props 中给第一行或目标行加上锚点使整行被聚光灯罩住mantineTableBodyRowProps: ({ row }) row.index 0 ? { data-tour: feature-row } : {},看板Kanban场景则在卡片容器上加data-tour属性参考 ReviewKanbanBoard.tsx 第 634 行附近。步骤 4渲染导览与重放按钮Button variantsubtle leftSection{MantineIcon icon{IconRoute} /} onClick{startTour} Take the tour /Button GuidedTour steps{steps} opened{isOpen} onClose{closeTour} /参考实现在页面右上角操作区渲染了带IconRoute图标的 Take the tour 按钮并把GuidedTour渲染在页面根部AiReviewsSettingsPage.tsx。注意该页面还做了一个小技巧导览只在看板视图上有可解析锚点因此effectiveView isTourOpen ? board : view导览运行期间强制切到看板结束后恢复用户存储的视图偏好useLocalStorage(ld.aiReviews.view)。步骤 5可选确定性示例数据让导览在空页面或任何页面上始终高亮同样的行。在onboarding/exampleData.ts中放置稳定、标签清晰的 mock 行和isExample辅助函数并在导览打开期间通过select注入const select useOnboardingMock(EXAMPLE_ROWS, isOpen); const { data } useThings(args, { select }); // hook 必须把 select 转发给 useQuery示例行的渲染必须看起来和用起来都明显不是真的整体弱化muted、禁用所有交互操作按钮禁用、不可导航、打上 Example 徽标交互能力用哨兵 id 门控如id.startsWith(example:)。参考实现 exampleData.ts 完全遵循这一约定哨兵前缀const EXAMPLE_REVIEW_ITEM_PREFIX example:isExampleReviewItem(uuid)判断uuid.startsWith(example:)三张样例卡分别对应看板生命周期To DowritebackEligible: true显示导览要指的 Start 按钮、In ProgressPR 已开、workspace 可跟进makeExampleRemediation生成preview_ready修复记录、Done已合并resolved所有 uuid、PR 链接、thread、project 均为哨兵前缀拼接的假坐标如example:in-progress:pr确保没有任何真实跳转可能表格中示例行通过isExampleReviewItem判定后在 Cause 列渲染灰色Exampletoken 徽标见 AiAgentAdminReviewItemsTable.tsx。看板端则直接按开关替换数据源ReviewKanbanBoard.tsx注释点明关键决策把示例数据绑定到导览是否打开而非列表是否为空这样即使在已有数据的看板上每次运行也能高亮同一批卡片。五、编写约定Conventions零依赖不引入 joyride / driver / intro.js 等第三方库聚光灯就是box-shadow: 0 0 0 9999px的压暗层已由GuidedTour内部处理。storageKey 命名ld.feature.tour.vn功能重新设计后把版本号 1 即可让已看过旧版的用户重新看到导览。文案温暖、自然、直奔要点不用破折号em dashes、不用箭头符号标题要短。参考实现中REVIEWS_TOUR_STEPS的文案均为短标题 一两句说明如 Start here / These are answers your agents probably got wrong...。样式遵循frontend-style-guide—— 不使用styleprop运行时几何信息通过__vars传递如--tour-top、--tour-card-left等 CSS 变量使用 CSS Modules消费主题 tokenldGray/ldDark。mock 行绝不能看起来或行为像真实数据弱化、带 Example 徽标、禁用操作。六、踩坑清单Gotchas延迟渲染的目标GuidedTour会为每一步轮询目标元素未出现时先显示居中卡片。不要在打开导览时过滤步骤——那会丢掉目标还没渲染出来的步骤。确定性优先如果希望每次运行都高亮同样的行把 mock 数据绑定到isOpen导览运行中而不是绑定到列表为空关闭导览立即切回真实数据。select透传数据 hook 必须接受并把select选项转发给useQuery参考useAiAgentAdminReviewItems。如果目标 hook 没有该参数需要先补上。七、扩展阅读路径套件入口与类型components/common/GuidedTour/GuidedTour.tsxGuidedTourStep全部字段、index.ts状态 hookuseGuidedTour.ts、useOnboardingMock.ts端到端参考实现AiReviewsSettingsPage.tsx、AiAgentAdminReviewItemsTable.tsx、ReviewKanbanBoard.tsx 与 onboarding/测试GuidedTour.test.tsx、ReviewsLoopDiagram.test.tsx给 Lightdash 前端功能接入导览时记住一句话即可起步套件只做怎么展示内容只写讲什么——状态与渲染交给三个构建块文案与锚点放进onboarding/示例数据永远打上标记并与导览开关绑定。【免费下载链接】lightdashAgentic BI. Analytics at the speed of code ⚡️项目地址: https://gitcode.com/GitHub_Trending/li/lightdash创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表