关于 react-joyride
React Joyride 是用于在 React 应用界面中创建引导式导览的库,提供 Hook 和组件 API,并支持配置步骤、异步钩子、事件处理及 UI 定制。
主要功能
- 01Hook 和组件 API
- 02可配置导览步骤与目标
- 03异步前后置钩子
- 04事件处理与程序化控制
- 05样式和组件定制
适用场景
- 01引导用户熟悉应用界面
- 02通过多步骤导览说明控件
- 03显示步骤前等待界面变化
- 04跟踪导览进度与事件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gilbarbara/ react-joyride --skill react-joyride安装后在 Claude Code 中输入/react-joyride确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api-events-components.mdapi-props-options.mdapi-step-state-controls.mdpatterns.md详细介绍
React Joyride v3
在 React 应用中创建引导式游览。提供两种公共 API:useJoyride() Hook(推荐)和 <Joyride> 组件。
在线文档:https://v3.react-joyride.com
快速开始
使用 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>;
}
使用组件
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 }。在 JSX 中渲染 Tour。
文档:https://v3.react-joyride.com/docs/getting-started
核心概念
游览有两个状态维度:
游览状态:idle -> ready -> waiting -> running <-> paused -> finished | skipped
idle:未加载步骤ready:步骤已加载,等待run: truewaiting:run=true,但步骤正在异步加载(步骤到达后转换为running)running:游览进行中paused:游览已暂停(受控模式下处于 COMPLETE 状态,或已调用stop())finished/skipped:游览已结束
步骤生命周期(每个步骤):init -> ready -> beacon_before -> beacon -> tooltip_before -> tooltip -> complete
*_before阶段:在此期间进行滚动和定位beacon:显示脉冲指示器(在continuous模式下导航、设置skipBeacon或placement: 'center'时跳过)tooltip:工具提示可见且可交互
文档:https://v3.react-joyride.com/docs/how-it-works
步骤配置
每个步骤都需要 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
}
目标类型
// CSS selector
{ target: '.sidebar-nav' }
// HTMLElement
{ target: document.getElementById('my-el') }
// React ref
const ref = useRef(null);
{ target: ref }
// Function (evaluated each lifecycle)
{ target: () => document.querySelector('.dynamic-element') }
常用步骤选项(可逐步覆盖)
| 选项 | 默认值 | 描述 |
|---|---|---|
placement | 'bottom' | 工具提示的位置。使用 'center' 可采用模态框样式(需要 target: 'body') |
skipBeacon | false | 跳过信标,直接显示工具提示 |
buttons | ['back','close','primary'] | 工具提示中的按钮。添加 'skip' 可显示跳过按钮 |
hideOverlay | false | 不显示暗色遮罩 |
blockTargetInteraction | false | 禁止点击高亮元素 |
before | - | (data) => Promise<void> — 步骤显示前运行的异步 Hook |
after | - | (data) => void — 步骤完成后运行的即发即弃 Hook |
skipScroll | false | 不滚动到目标 |
scrollTarget | - | 滚动到此元素,而不是 target |
spotlightTarget | - | 高亮此元素,而不是 target |
spotlightPadding | 10 | 聚光灯周围的内边距。可使用数字或 { top, right, bottom, left } |
targetWaitTimeout | 1000 | 等待目标出现的时间(毫秒)。0 = 不等待 |
beforeTimeout | 5000 | 等待 before Hook 的时间(毫秒)。0 = 不设超时 |
所有 Options 字段都可以通过 options 属性全局设置,也可以逐步设置。逐步设置的值会覆盖全局设置。
文档:https://v3.react-joyride.com/docs/step | https://v3.react-joyride.com/docs/props/options
非受控与受控模式
非受控模式(默认 — 强烈推荐)
游览会在内部管理步骤导航。大多数使用场景都适合此模式。
该库会为你处理异步转换。 如果某个步骤需要等待 UI 变化(下拉菜单展开、数据加载、动画),请使用 before Hook — 游览会等待 Promise 解析后再显示步骤。如果目标元素尚未出现在 DOM 中,targetWaitTimeout(默认值:1000ms)会负责轮询。此类情况无需使用受控模式。
const { Tour } = useJoyride({
continuous: true,
run: isRunning,
steps: [
{ target: '.nav', content: 'Navigation' },
{
target: '.dropdown-item',
content: 'Inside the dropdown',
before: () => {
// Open dropdown and wait for animation — tour waits automatically
openDropdown();
return new Promise(resolve => setTimeout(resolve, 300));
},
after: () => closeDropdown(), // Clean up after step (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 Hook 处理的复杂多组件协调)。
const [stepIndex, setStepIndex] = useState(0);
const [run, setRun] = useState(true);
const { Tour } = useJoyride({
continuous: true,
run,
stepIndex, // This makes it controlled
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/afterHook 的非受控模式
事件系统
onEvent 回调
onEvent: (data: EventData, controls: Controls) => void
data 对象包含完整的引导状态以及事件特有的字段。controls 对象允许你以编程方式控制引导。
事件类型(按每个步骤的顺序)
| 事件 | 触发时机 |
|---|---|
tour:start | 引导开始 |
step:before_hook | 调用 before 钩子 |
step:before | 找到目标,即将渲染步骤 |
scroll:start | 正在滚动到目标 |
scroll:end | 滚动完成 |
beacon | 显示信标 |
tooltip | 显示工具提示 |
step:after | 用户进行了导航(下一步/上一步/关闭/跳过) |
step:after_hook | 调用 after 钩子 |
tour:end | 引导已结束或跳过 |
tour:status | 状态已更改(停止/重置时) |
error:target_not_found | 未找到目标元素 |
error | 通用错误 |
使用 on() 订阅事件
const { on, Tour } = useJoyride({ ... });
useEffect(() => {
const unsubscribe = on('tooltip', (data, controls) => {
analytics.track('tour_step_viewed', { step: data.index });
});
return unsubscribe;
}, [on]);
文档:https://v3.react-joyride.com/docs/events
控制方法
可通过 useJoyride() 的返回值或 onEvent 的第二个参数使用:
| 方法 | 说明 |
|---|---|
next() | 前进到下一步 |
prev() | 返回上一步 |
close(origin?) | 关闭当前步骤并前进 |
skip(origin?) | 完全跳过引导 |
start(index?) | 开始引导 |
stop(advance?) | 停止(暂停)引导 |
go(index) | 跳转到指定步骤(仅非受控模式) |
reset(restart?) | 重置引导(仅非受控模式) |
open() | 打开当前步骤的工具提示 |
info() | 获取当前状态 |
文档:https://v3.react-joyride.com/docs/hook
样式与主题
三种自定义层级(从简单到完全控制):
1. 颜色选项(最简单)
options: {
primaryColor: '#1976d2', // Buttons and beacon
backgroundColor: '#1a1a2e', // Tooltip background
textColor: '#ffffff', // Tooltip text
overlayColor: 'rgba(0,0,0,0.7)', // Overlay backdrop
arrowColor: '#1a1a2e', // Arrow (match background)
}
2. 样式覆盖
styles: {
tooltip: { borderRadius: 12 },
buttonPrimary: { backgroundColor: '#1976d2' },
buttonBack: { color: '#666' },
spotlight: { borderRadius: 8 },
}
样式键:arrow、beacon、beaconInner、beaconOuter、beaconWrapper、buttonBack、buttonClose、buttonPrimary、buttonSkip、floater、loader、overlay、tooltip、tooltipContainer、tooltipContent、tooltipFooter、tooltipFooterSpacer、tooltipTitle
3. 自定义组件(完全控制)
请参阅下一节。
文档:https://v3.react-joyride.com/docs/props/styles
自定义组件
通过 props 替换任意 UI 组件。每个组件都会接收包含步骤数据和按钮处理程序的渲染 props。
自定义工具提示
import 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>
);
}
// Usage
<Joyride tooltipComponent={MyTooltip} ... />
重要:在容器上展开 tooltipProps(用于设置 role="dialog" 和 aria-modal)。在按钮上展开按钮 props(backProps、primaryProps、closeProps、skipProps),以正确处理操作。
自定义信标
必须渲染一个 <span>(置于 <button> 包装元素内)。接收 BeaconRenderProps:{ continuous, index, isLastStep, size, step }。
自定义箭头
接收 ArrowRenderProps:{ base, placement, size }。
自定义加载器
接收 LoaderRenderProps:{ step }。设为 null 可禁用加载器。
文档:https://v3.react-joyride.com/docs/custom-components
问题 → 解决方案指南
| 我需要…… | 使用 |
|---|---|
| 在步骤之间等待 UI 异步变化(下拉菜单、动画、数据加载) | 返回 Promise 的 before 钩子 — 而非受控模式 |
| 从外部控制步骤导航(URL 同步、外部状态机) | 使用 stepIndex 的受控模式 — 但请先尝试 before/after 钩子 |
| 跟踪失败的步骤(目标缺失、钩子错误) | useJoyride() 返回值中的 failures 数组 |
无需使用 onEvent 分支即可监听特定事件 | 使用 useJoyride() 返回值中的 on('event:type', handler) |
| 显示居中的模态框样式步骤 | target: 'body' + placement: 'center' |
常见问题与调试
首先使用 debug: true
debug prop 是最强大的故障排查工具。它会在控制台中记录详细的生命周期转换、状态更改和事件触发情况。遇到问题时,请务必从这里开始排查。
<Joyride debug={true} ... />
// or
useJoyride({ debug: true, ... })
控制台输出会准确显示引导到达了哪个生命周期阶段、触发了哪些操作,以及卡在了哪里。
引导未启动
- 检查是否设置了
run={true} - 确认
steps数组不为空,且各步骤的target和content有效 - 对于 SSR:使用
<Joyride>组件(会自动保护 DOM 访问),或检查typeof window !== 'undefined'
找不到目标
- 在控制台中测试选择器:
document.querySelector('.your-selector') - 元素必须可见(不能设置为
display: none、visibility: hidden,也不能尺寸为零) - 如果元素稍后才挂载,请增大
targetWaitTimeout(默认值:1000ms) - 设置
targetWaitTimeout: 0可完全跳过等待 - 在非受控模式下,缺失的目标会自动跳到下一步;在受控模式下,处理
error:target_not_found事件
工具提示始终不显示 / 遮罩闪烁
- 添加
debug: true并查看控制台,确认到达了哪个生命周期阶段 - 确认目标元素位于视口内或可滚动区域内
- 检查祖先元素是否设置了会裁切目标的 CSS
overflow: hidden - 如果使用了 portal 或模态框,目标可能无法访问
受控模式卡住
- 首先要问:你确实需要受控模式吗?大多数异步需求都可以通过非受控模式下的
before/after钩子解决 - 如果使用受控模式:在
onEvent处理程序中,当type === 'step:after'时,必须更新stepIndex - 同时处理前进(
action !== 'prev')和后退(action === 'prev')导航 - 还要处理
error:target_not_found,以跳过无法正常运行的步骤 go()和reset()在受控模式下无效
Before 钩子超时
- 默认
beforeTimeout为 5000ms;如果异步操作耗时更长,请增大该值 - 设置
beforeTimeout: 0可禁用超时 - 等待期间,经过
loaderDelay(300ms)后会显示加载指示器
滚动问题
- 使用
scrollTarget,滚动到不同于工具提示目标的元素 - 调整
scrollOffset(默认值:20px),以适应页眉或固定元素 - 设置
skipScroll: true可禁用某一步骤的自动滚动 scrollToFirstStep: false为默认值;如果第一步在屏幕外,请将其设为true
居中放置
- 将
placement: 'center'与target: 'body'搭配使用,可显示模态框样式的居中工具提示 - 居中放置会自动隐藏信标和箭头
导入
// Named exports only (no default export in v3)
import { Joyride, useJoyride } from 'react-joyride';
// Constants for type-safe comparisons
import { ACTIONS, EVENTS, LIFECYCLE, ORIGIN, STATUS } from 'react-joyride';
// Types
import type { Step, Props, EventData, Controls, TooltipRenderProps } from 'react-joyride';
文档:https://v3.react-joyride.com/docs/exports
参考文件
请阅读以下文件,了解完整的 API 详情:
references/api-props-options.md— 完整的 Props、Options(包含所有 30 多个字段及其默认值)、Locale、FloatingOptions 和 Styles 类型references/api-step-state-controls.md— Step、StepMerged、StepTarget、State、Controls(全部 10 个方法)、UseJoyrideReturn、StepFailurereferences/api-events-components.md— 全部 13 种事件类型、ACTIONS/LIFECYCLE/STATUS/ORIGIN 常量、EventData、自定义组件渲染属性references/patterns.md— 完整的可运行示例:受控模式、before/after 钩子、自定义工具提示、事件订阅、动态步骤