
前端UI组件【免费下载链接】react-joyrideCreate guided tours in your apps项目地址https://gitcode.com/gh_mirrors/re/react-joyride点击查看免费下载本文是 React Joyride v3当前仓库 react-joyride 的核心能力的完整技术指南覆盖useJoyride()Hook 与Joyride组件两套公开 API、Step 与 Options 的完整配置项、Tour Status 与 Step Lifecycle 双状态机、事件系统、程序化 Controls、三种样式定制层级以及常见问题排障方案。读完本文你将能在自己的 React 应用中独立实现、配置、调试一条从启动到结束的引导式导览onboarding tour / product tour / walkthrough。说明本仓库中skills/react-joyride/SKILL.md及其references/目录api-props-options.md、api-step-state-controls.md、api-events-components.md、patterns.md是官方技能文档的主体本文以它为骨架并用 src 下的源码实现做印证与扩充。快速开始两套公开 APIReact Joyride v3 只导出命名导出没有 default export提供两个入口useJoyride()Hook —— 官方推荐Joyride组件 —— 声明式用法且内置 SSR 保护。方式一使用useJoyride()Hook推荐import { useJoyride, STATUS, Status } from react-joyride; function App() { const { Tour } useJoyride({ continuous: true, run: true, steps: [ { target: .my-element, content: This is the first step, title: Welcome }, { target: #sidebar, content: Navigate here, placement: right }, ], onEvent: (data) { if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(data.status)) { // Tour ended } }, }); return div{Tour}{/* rest of app */}/div; }方式二使用Joyride组件import { Joyride, STATUS, Status } from react-joyride; function App() { return ( Joyride continuous run{true} steps{[ { target: .my-element, content: First step }, { target: #sidebar, content: Second step }, ]} onEvent{(data) { if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(data.status)) { // Tour ended } }} / ); }Hook 的返回值结构为{ controls, failures, on, state, step, Tour }其中Tour是一个 ReactElement必须在你的 JSX 中渲染出来导览才会出现。从源码看Joyride组件本身只是useJoyride(props)的一层薄封装见 src/index.tsx它先用canUseDOM()判断是否处于浏览器环境SSR 或预渲染阶段直接返回null因此服务端渲染场景下组件更安全。核心概念双状态机一次导览由两个正交的状态维度驱动理解它们是排查所有问题的基础。Tour Status整场导览的宏观状态idle - ready - waiting - running - paused - finished | skipped状态含义idle没有加载任何步骤steps 为空ready步骤已加载等待run: truewaitingruntrue但步骤还在异步加载中步骤到达后自动转入runningrunning导览正在运行paused导览暂停受控模式下停在 COMPLETE或调用stop()后finished/skipped导览结束完成或跳过实现印证在 src/modules/store.ts 的Store构造函数中初始状态即根据steps.length决定STATUS.READY或STATUS.IDLEapplyTransitionssrc/modules/store.ts实现了waiting - running的自动迁移——只要waiting状态下 size 大于 0就自动置为RUNNING。Step Lifecycle单个步骤的微观阶段init - ready - beacon_before - beacon - tooltip_before - tooltip - complete*_before阶段滚动与定位在此发生beacon显示脉冲指示点当continuous导航中、设置了skipBeacon、或placement: center时跳过tooltip气泡提示可见且可交互。Step 配置每个 Step 必填target和content其余字段均可选{ target: .my-element, // CSS selector, HTMLElement, React ref, or () HTMLElement content: Step body text, // ReactNode title: Optional title, // ReactNode placement: bottom, // Default. Also: top, left, right, *-start, *-end, auto, center id: unique-id, // Optional identifier data: { custom: data }, // Attached to event callbacks }Target 的四种写法// CSS selector { target: .sidebar-nav } // HTMLElement { target: document.getElementById(my-el) } // React ref const ref useRef(null); { target: ref } // Function每次生命周期重新求值 { target: () document.querySelector(.dynamic-element) }从类型定义看StepTarget就是这四种联合见 api-step-state-controls.md函数形式适合动态出现的元素因为它在每次生命周期阶段都会被重新求值。常用 Step 选项可逐步骤覆盖Option默认值说明placementbottom气泡位置。center为模态风格需配合target: bodyskipBeaconfalse跳过 beacon直接显示气泡buttons[back,close,primary]气泡中的按钮。加skip可显示跳过按钮hideOverlayfalse不显示深色遮罩blockTargetInteractionfalse阻止高亮元素的点击交互before-(data) Promisevoid步骤显示前的异步钩子after-(data) void步骤完成后的即弃钩子skipScrollfalse不滚动到目标scrollTarget-滚动到该元素而非targetspotlightTarget-高亮该元素而非targetspotlightPadding10聚光灯周围内边距。数字或{ top, right, bottom, left }targetWaitTimeout1000等待目标出现的毫秒数。0 不等待beforeTimeout5000等待before钩子的毫秒数。0 无超时所有 Options 字段既可通过全局optionsprop 设置也可在单个 step 内覆盖step 级覆盖全局。该合并逻辑在 src/modules/step.ts 的getMergedStep中实现defaultOptions见 src/defaults.ts→ 全局props.options→ 当前 step 自身字段逐层 deepMerge最终产出StepMerged所有 Options 字段均已填充默认值的归一化步骤事件回调和自定义组件 props 里拿到的就是它。非受控 vs 受控非受控模式默认强烈推荐导览内部自主管理步骤导航适合绝大多数场景。库会替你处理异步过渡某个步骤需要等待 UI 变化下拉展开、数据加载、动画完成时用before钩子——导览会等 Promise resolve 后再显示该步骤目标元素尚未挂载到 DOM 时targetWaitTimeout默认 1000ms会轮询等待它出现这两种情况都不需要受控模式。const { Tour } useJoyride({ continuous: true, run: isRunning, steps: [ { target: .nav, content: Navigation }, { target: .dropdown-item, content: Inside the dropdown, before: () { // 打开下拉并等待动画 —— 导览会自动等待 openDropdown(); return new Promise(resolve setTimeout(resolve, 300)); }, after: () closeDropdown(), // 步骤结束后清理fire-and-forget }, { target: .main-content, content: Main content }, ], onEvent: (data) { if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(data.status)) { setIsRunning(false); } }, });受控模式配合stepIndex—— 谨慎使用仅当父组件确实需要在外部管理步骤索引时才使用例如与 URL 参数同步、外部状态机、或before/after钩子搞不定的复杂多组件协调。const [stepIndex, setStepIndex] useState(0); const [run, setRun] useState(true); const { Tour } useJoyride({ continuous: true, run, stepIndex, // 传入 stepIndex 即进入受控模式 steps, onEvent: (data) { const { action, index, status, type } data; if (([STATUS.FINISHED, STATUS.SKIPPED] as Status).includes(status)) { setRun(false); return; } if (type step:after || type error:target_not_found) { setStepIndex(index (action prev ? -1 : 1)); } }, });受控模式规则go()和reset()被禁用会打印警告日志你必须在事件回调里更新stepIndex导览在 COMPLETE 处暂停必须由你推进除非有强理由需要外部索引管理否则优先用非受控模式 before/after钩子。实现印证Store构造时通过is.number(stepIndex)判断是否受控src/modules/store.ts受控模式下initialStepIndex会被忽略并打印提示useControls中go/reset都会先检查controlled若为受控模式则仅打日志并直接返回src/hooks/useControls.ts。受控模式更新索引时还会经过updateState的resolvedIndex逻辑——受控且未强制索引时外部传入的index变更不会覆盖内部状态src/modules/store.ts。事件系统onEvent回调onEvent: (data: EventData, controls: Controls) voiddata对象包含完整导览状态外加事件专属字段controls对象让你能程序化控制导览。EventData的完整结构含type判别字段、error、scroll、waiting等见 api-events-components.md其基础载荷TourData同时也会传给before/after钩子包含action、index、lifecycle、origin、size、status、step、controlled等字段。每个步骤的事件顺序事件触发时机tour:start导览开始step:before_hookbefore钩子被调用step:before找到目标即将渲染步骤scroll:start开始滚动到目标scroll:end滚动完成beaconbeacon 显示tooltip气泡显示step:after用户导航next/prev/close/skipstep:after_hookafter钩子被调用tour:end导览完成或跳过tour:status状态变更stop/reset 时error:target_not_found未找到目标元素error通用错误对应的事件类型常量EVENTS在 src/literals/index.ts 中定义与文档完全一致。事件订阅在Store里通过Mapstring, SetEventHandler管理同一事件可挂多个订阅者且单个订阅者抛错不会影响其他订阅者或导览本身fire-and-forget见 src/modules/store.ts。用on()订阅特定事件const { on, Tour } useJoyride({ ... }); useEffect(() { const unsubscribe on(tooltip, (data, controls) { analytics.track(tour_step_viewed, { step: data.index }); }); return unsubscribe; }, [on]);on()返回取消订阅函数适合在 useEffect 中做埋点、日志等横切关注点而无需在onEvent里写一大串 switch。Controls程序化控制useJoyride()返回值或onEvent第二参数均可拿到Controls完整类型见 api-step-state-controls.md方法说明next()前进到下一步prev()回到上一步close(origin?)关闭当前步骤并前进skip(origin?)整体跳过导览start(index?)启动导览可指定起始索引stop(advance?)停止暂停导览go(index)跳转到指定步骤仅非受控reset(restart?)重置导览仅非受控restarttrue时同时重新启动open()打开当前步骤的气泡跳过 beaconinfo()获取当前状态快照实现层面useControlssrc/hooks/useControls.ts每次方法调用都是对store.updateState(...)的一次补丁式状态提交例如next()用getUpdatedIndex(index 1, size)做边界夹取Math.min(Math.max(nextIndex, 0), size)并把lifecycle置为COMPLETE、重置positioned/scrolling/waitingstop(advance)若advancetrue会先前进一个索引再置PAUSEDskip()直接把状态置为STATUS.SKIPPED。所有方法在非RUNNING状态下调用都会静默返回避免非法操作。样式与主题三层定制从简单到完全控制共三层第一层颜色选项最简单options: { primaryColor: #1976d2, // 按钮和 beacon backgroundColor: #1a1a2e, // 气泡背景 textColor: #ffffff, // 气泡文字 overlayColor: rgba(0,0,0,0.7), // 遮罩背景 arrowColor: #1a1a2e, // 箭头与背景一致 }第二层styles 覆盖styles: { tooltip: { borderRadius: 12 }, buttonPrimary: { backgroundColor: #1976d2 }, buttonBack: { color: #666 }, spotlight: { borderRadius: 8 }, }完整的样式键共 19 个arrow、beacon、beaconInner、beaconOuter、beaconWrapper、buttonBack、buttonClose、buttonPrimary、buttonSkip、floater、loader、overlay、tooltip、tooltipContainer、tooltipContent、tooltipFooter、tooltipFooterSpacer、tooltipTitle类型定义见 api-props-options.md。Styles接受PartialDeepStyles只需覆盖需要的键。第三层自定义组件完全控制见下一节。自定义组件任何 UI 部件都能通过 props 替换每个组件都接收带有步骤数据与按钮处理函数的 render props。自定义 Tooltipimport type { TooltipRenderProps } from react-joyride; function MyTooltip({ backProps, index, primaryProps, size, skipProps, step, tooltipProps }: TooltipRenderProps) { return ( div {...tooltipProps} style{{ background: #fff, padding: 16, borderRadius: 8, width: step.width }} {step.title h3{step.title}/h3} div{step.content}/div div {index 0 button {...backProps}Back/button} button {...primaryProps}Next/button /div /div ); } // 用法 Joyride tooltipComponent{MyTooltip} ... /重要必须在容器上展开tooltipProps它会设置roledialog与aria-modal按钮 propsbackProps、primaryProps、closeProps、skipProps必须展开在对应按钮上动作处理才会正确。自定义 Beacon必须渲染一个span因为它被放进button包裹层里。接收BeaconRenderProps{ continuous, index, isLastStep, size, step }。自定义 Arrow接收ArrowRenderProps{ base, placement, size }。自定义 Loader接收LoaderRenderProps{ step }。设置为null可完全禁用 loader。完整自定义 Tooltip 模式配合step.buttons和isLastStep可以做更完整的产品级气泡完整示例见 patterns.mdfunction CustomTooltip({ backProps, closeProps, index, isLastStep, primaryProps, size, skipProps, step, tooltipProps }: TooltipRenderProps) { return ( div {...tooltipProps} style{{ background: #fff, borderRadius: 8, maxWidth: 400, padding: 20, width: step.width }} {step.title h3 style{{ margin: 0 0 8px }}{step.title}/h3} div{step.content}/div div style{{ display: flex, justifyContent: space-between, marginTop: 16 }} {step.buttons.includes(skip) !isLastStep ( button {...skipProps} typebuttonSkip/button )} div style{{ display: flex, gap: 8, marginLeft: auto }} {index 0 button {...backProps} typebuttonBack/button} button {...primaryProps} typebutton {isLastStep ? Done : Next (${index 1}/${size})} /button /div /div /div ); }问题 → 解决方案速查我需要……用什么在步骤间等待异步 UI 变化下拉、动画、数据加载before钩子返回 Promise —— 而不是受控模式在外部控制步骤导航URL 同步、外部状态机受控模式 stepIndex—— 但先试试before/after钩子追踪哪些步骤失败了目标缺失、钩子报错useJoyride()返回的failures数组监听特定事件而不写onEvent大 switchon(event:type, handler)展示居中的模态风格步骤target: bodyplacement: centerfailures数组的元素是{ reason: before_hook | target_not_found, step: StepMerged }并在start()/reset()时清空src/hooks/useTourEngine.ts 中addFailure/clearFailures的实现印证。常见坑与调试第一步开启debug: truedebugprop 是最强大的排障工具它会把完整生命周期流转、状态变更、事件发射打到控制台精确告诉你导览卡在哪个阶段、触发了什么 action。Joyride debug{true} ... / // 或 useJoyride({ debug: true, ... })控制台输出会显示导览到达了哪个生命周期阶段、哪些 action 正在触发、以及卡在哪里。导览不启动确认设置了run{true}确认steps数组非空且每个 step 都有合法的target和contentSSR 场景用Joyride组件自动保护 DOM 访问或检查typeof window ! undefined。实现印证导览启动时validateSteps会逐条校验 step 是否为对象且存在target不合法时打印target is missing from the step之类的警告并拒绝启动src/modules/step.ts。找不到目标在控制台测试选择器document.querySelector(.your-selector)元素必须可见不能是display: none、visibility: hidden或零尺寸元素晚挂载时调大targetWaitTimeout默认 1000ms设targetWaitTimeout: 0完全跳过等待非受控模式下目标缺失会自动前进受控模式下需处理error:target_not_found事件。气泡不出现 / 遮罩闪烁加debug: true看控制台到达了哪个生命周期阶段确认目标元素在视口内或可滚动到检查祖先元素是否有overflow: hidden裁切了目标使用 portal 或 modal 时目标可能不可达可用portalElementprop 指定渲染容器。受控模式卡住先问自己真的需要受控模式吗多数异步需求用非受控模式 before/after钩子就能解决若必须受控type step:after时必须在onEvent中更新stepIndex同时处理前进action ! prev和后退action prev两种方向也要处理error:target_not_found以跳过坏步骤受控模式下go()和reset()不可用。before 钩子超时默认beforeTimeout为 5000ms异步操作更久就调大它设beforeTimeout: 0表示无超时等待期间超过loaderDelay300ms后会出现 loader。滚动问题用scrollTarget滚动到不同于气泡目标的元素调整scrollOffset默认 20px应对固定头部或固定元素单步设skipScroll: true禁用自动滚动scrollToFirstStep默认false第一步在屏幕外时设为true。center 居中放置用placement: centertarget: body实现模态风格居中气泡center 放置会自动隐藏 beacon 和箭头。导入规范// v3 只有命名导出没有 default export import { Joyride, useJoyride } from react-joyride; // 类型安全比较用的常量 import { ACTIONS, EVENTS, LIFECYCLE, ORIGIN, STATUS } from react-joyride; // 类型 import type { Step, Props, EventData, Controls, TooltipRenderProps } from react-joyride;注意ORIGIN常量包含button_back、button_close、button_primary、button_skip、keyboard、overlay六个取值src/literals/index.ts可用于事件追踪中判断用户通过哪个入口触发的动作。常用实战模式异步数据加载后再展示步骤{ target: .user-profile, content: Here is your profile data, before: async () { await fetchUserProfile(); // 导览会等这个 Promise resolve }, beforeTimeout: 10000, // 允许最长 10s }步骤完成后的埋点{ target: .feature, content: Check out this feature, after: (data) { // fire-and-forget不阻塞导览 analytics.track(tour_step_completed, { stepIndex: data.index, action: data.action, }); }, }仅前进时延迟后退不延迟{ target: .sidebar, content: The sidebar, before: ({ action }) { const ms action ACTIONS.PREV ? 0 : 300; return new Promise(resolve setTimeout(resolve, ms)); }, }动态步骤按角色/特性开关构建const [steps, setSteps] useStateStep[]([]); useEffect(() { const dynamicSteps: Step[] [ { target: .dashboard, content: Welcome to your dashboard }, ]; if (user.isAdmin) { dynamicSteps.push({ target: .admin-panel, content: Admin controls are here }); } if (featureFlags.newSearch) { dynamicSteps.push({ target: .search-bar, content: Try the new search }); } setSteps(dynamicSteps); }, [user, featureFlags]); return Joyride run{steps.length 0} steps{steps} continuous /;用 React ref 作目标const sidebarRef useRefHTMLDivElement(null); const buttonRef useRefHTMLButtonElement(null); const steps: Step[] [ { target: sidebarRef, content: Navigation sidebar }, { target: buttonRef, content: Click here to create }, { target: .css-selector, content: Mix refs with selectors }, ]; return ( div Joyride steps{steps} run continuous / div ref{sidebarRef}Sidebar/div button ref{buttonRef}Create/button span classNamecss-selectorOther element/span /div );重新开始 / 续播导览const [run, setRun] useState(false); const [initialStepIndex, setInitialStepIndex] useState(0); const handleStart () { setInitialStepIndex(0); setRun(true); }; const handleResume (fromStep: number) { setInitialStepIndex(fromStep); setRun(true); }; return ( div Joyride run{run} initialStepIndex{initialStepIndex} steps{steps} continuous onEvent{(data) { if ([STATUS.FINISHED, STATUS.SKIPPED].includes(data.status)) { setRun(false); } }} / button onClick{handleStart}Start Tour/button button onClick{() handleResume(3)}Resume from Step 4/button /div );模态风格居中步骤{ target: body, placement: center, content: ( div h2Welcome!/h2 pThis appears as a centered modal overlay./p /div ), // center 放置会自动隐藏 beacon 和箭头 }完整 API 参考索引本文是 React Joyride v3 的实战入门与排障指南。若要查阅完整 API 细节仓库内还有四份结构化参考文档可继续深读api-props-options.md —— 完整 Props、Options全部 30 字段及默认值、Locale、FloatingOptions、Styles 类型api-step-state-controls.md —— Step、StepMerged、StepTarget、State、Controls全部 10 个方法、UseJoyrideReturn、StepFailureapi-events-components.md —— 全部 13 种事件类型、ACTIONS/LIFECYCLE/STATUS/ORIGIN 常量、EventData、自定义组件 render propspatterns.md —— 完整可运行示例受控模式、before/after 钩子、自定义气泡、事件订阅、动态步骤。仓库中 website/src/app/demos 目录下还有覆盖 overview、carousel、chat、controlled、custom-components、modal、multi-route、scroll 等场景的真实示例页面对应 e2e 下的端到端测试可直接对照学习src 下的组件、hooks 与 modules 是这套 API 的全部实现源码。赞分享前端UI组件【免费下载链接】react-joyrideCreate guided tours in your apps项目地址https://gitcode.com/gh_mirrors/re/react-joyride点击查看免费下载相关推荐LaMa 界面与控件样式定制完整指南改对 7 处配置交互面板贴合自己的工作流LaMa 界面与控件样式定制完整指南改对 7 处配置交互面板贴合自己的工作流 LaMa 是 WACV 2022 论文开源的大面积掩膜图像修复项目自带交互式人工智能计算机视觉深度学习图像处理Hermes WebUI 会话管理指南创建、分组与备份Hermes WebUI 会话管理指南创建、分组与备份 Hermes WebUI 会话管理围绕左侧边栏的会话列表展开它是一款 Hermes Agent 的自人工智能AI 应用AI Agent交互助手MCP 服务前端Civitai 引导式导览Guided Tours系统实现解析基于 react-joyride 的产品上手引导架构Civitai 引导式导览Guided Tours系统实现解析基于 react joyride 的产品上手引导架构 导读 本文深入解析 Civitai 前后端前端AI 应用上一篇VPP API完全指南从基础调用到高级功能实现下一篇C类型推导完全指南如何用auto关键字简化现代C编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考