mcpField
R
react-joyride

react-joyride

github.com/gilbarbara开发7.9k691 次安装16 周前更新
代码仓库

关于 react-joyride

React Joyride 是用于在 React 应用界面中创建引导式导览的库,提供 Hook 和组件 API,并支持配置步骤、异步钩子、事件处理及 UI 定制。

主要功能

  1. 01Hook 和组件 API
  2. 02可配置导览步骤与目标
  3. 03异步前后置钩子
  4. 04事件处理与程序化控制
  5. 05样式和组件定制

适用场景

  1. 01引导用户熟悉应用界面
  2. 02通过多步骤导览说明控件
  3. 03显示步骤前等待界面变化
  4. 04跟踪导览进度与事件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gilbarbara/react-joyride --skill react-joyride

安装后在 Claude Code 中输入/react-joyride确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api-events-components.md
api-props-options.md
api-step-state-controls.md
patterns.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: true
  • waiting: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')
skipBeaconfalse跳过信标,直接显示工具提示
buttons['back','close','primary']工具提示中的按钮。添加 'skip' 可显示跳过按钮
hideOverlayfalse不显示暗色遮罩
blockTargetInteractionfalse禁止点击高亮元素
before-(data) => Promise<void> — 步骤显示前运行的异步 Hook
after-(data) => void — 步骤完成后运行的即发即弃 Hook
skipScrollfalse不滚动到目标
scrollTarget-滚动到此元素,而不是 target
spotlightTarget-高亮此元素,而不是 target
spotlightPadding10聚光灯周围的内边距。可使用数字或 { top, right, bottom, left }
targetWaitTimeout1000等待目标出现的时间(毫秒)。0 = 不等待
beforeTimeout5000等待 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 / after Hook 的非受控模式

事件系统

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、StepFailure
  • references/api-events-components.md — 全部 13 种事件类型、ACTIONS/LIFECYCLE/STATUS/ORIGIN 常量、EventData、自定义组件渲染属性
  • references/patterns.md — 完整的可运行示例:受控模式、before/after 钩子、自定义工具提示、事件订阅、动态步骤

评论

支持 Markdown