# 最佳实践

URL: https://caijiao.org/driver-js/05-practices/02-best-practices
Source: docs/driver-js/05-practices/02-best-practices.md
Description: 总结 Driver.js 页面引导的设计原则、文案建议、可访问性、移动端适配、状态存储、埋点和常见问题排查。

Driver.js 可以很快做出页面引导，但真正影响体验的是设计和使用策略。好的引导应该帮助用户完成任务，而不是替产品界面解释所有问题。

## 保持步骤短

多数引导控制在 3 到 6 步更合适。步骤太多时，用户会快速跳过。

```js
const steps = [
  { element: "#create-project", popover: { title: "创建项目", description: "从这里开始。" } },
  { element: "#project-list", popover: { title: "项目列表", description: "这里查看项目状态。" } },
  { element: "#invite-member", popover: { title: "邀请成员", description: "把同事加入团队。" } },
];
```

如果确实有很多内容，可以拆成多个主题引导，例如“项目创建引导”“团队管理引导”“账单设置引导”。

## 文案写用户动作

弹层正文应该回答“用户接下来能做什么”。

| 不推荐 | 推荐 |
| --- | --- |
| “这是创建按钮” | “点击这里创建你的第一个项目” |
| “这是筛选器” | “用状态和负责人筛选需要处理的任务” |
| “这里是设置” | “在这里修改团队名称、成员权限和通知方式” |

标题负责定位，正文负责解释价值。

## 不要重复打扰用户

用本地或服务端状态记录已经看过的导览：

```js
const TOUR_KEY = "dashboard-tour-v1";

function shouldShowTour() {
  return !localStorage.getItem(TOUR_KEY);
}

function markTourShown() {
  localStorage.setItem(TOUR_KEY, "1");
}

const driverObj = driver({
  onDestroyed: markTourShown,
  steps,
});

if (shouldShowTour()) {
  driverObj.drive();
}
```

当产品界面发生较大变化时，可以更新 key，例如 `dashboard-tour-v2`。

## 让用户能退出

除非是合规确认或安全培训，否则应允许用户关闭导览。强制阅读通常会降低体验。

```js
const driverObj = driver({
  allowClose: true,
  overlayClickBehavior: "close",
  nextBtnText: "下一步",
  prevBtnText: "上一步",
  doneBtnText: "完成",
});
```

如果需要用户稍后再看，可以在页面上保留“帮助”“页面引导”入口。

## 移动端适配

移动端屏幕空间有限，弹层容易遮挡内容。建议：

- 减少步骤数量。
- 优先高亮大而稳定的区域。
- 避免高亮底部固定按钮和键盘附近元素。
- 在小屏幕下关闭非必要引导。

```js
const isSmallScreen = window.matchMedia("(max-width: 640px)").matches;

if (!isSmallScreen) {
  driver({ steps }).drive();
}
```

## 可访问性

页面引导不应阻止键盘用户或辅助技术用户完成任务。

- 不要只靠颜色表达重要信息。
- 弹层文案要简短明确。
- 引导结束后，焦点最好回到用户之前操作的区域。
- 对关键流程提供文档或帮助入口，不要只依赖弹层。

## 埋点指标

可以记录这些指标判断引导是否有效：

| 指标 | 用途 |
| --- | --- |
| 导览展示次数 | 判断触达量 |
| 每一步到达率 | 找出用户跳出的步骤 |
| 完成率 | 判断引导是否过长 |
| 引导后动作转化 | 例如创建项目、邀请成员、完成设置 |

示例：

```js
const driverObj = driver({
  onHighlighted: (_element, step) => {
    analytics.track("tour_step_viewed", {
      title: step.popover?.title,
    });
  },
  onDestroyed: () => {
    analytics.track("tour_closed");
  },
  steps,
});
```

## 常见问题排查

| 问题 | 可能原因 | 解决方式 |
| --- | --- | --- |
| 弹层没有样式 | 未引入 `driver.css` | 导入 `driver.js/dist/driver.css` |
| 目标元素没有高亮 | 选择器写错或元素尚未渲染 | 检查 DOM，必要时等待元素出现 |
| 弹层位置奇怪 | 目标元素太小、被隐藏或在滚动容器中 | 换更稳定的目标元素，检查布局 |
| 路由切换后遮罩残留 | 没有销毁实例 | 在组件卸载或路由切换时调用 `destroy()` |
| 用户总是跳过 | 步骤太多或文案无价值 | 缩短步骤，改写为动作导向文案 |

## 上线检查清单

- 已固定依赖版本。
- 默认 CSS 已引入。
- 中文按钮文案已配置。
- 所有目标元素在对应用户权限下都存在。
- 路由切换和组件卸载会清理实例。
- 移动端和窄屏已验证。
- 已读状态不会无限重复弹出。
- 关键数据已接入埋点或日志。
