Hooks 与事件

Driver.js 提供生命周期 hooks,让你在导览开始、步骤切换、弹层渲染、关闭销毁等时机执行业务逻辑。

Hooks 适合处理四类事情:

  • 记录用户是否看过引导。
  • 上报步骤浏览和完成埋点。
  • 在进入下一步前保存表单或打开面板。
  • 在路由切换、权限变化时清理导览。

常见 hooks

js
const driverObj = driver({
  onHighlightStarted: (element, step) => {
    console.log("开始高亮", element, step);
  },
  onHighlighted: (element, step) => {
    console.log("高亮完成", element, step);
  },
  onDeselected: (element, step) => {
    console.log("离开当前步骤", element, step);
  },
  onDestroyed: () => {
    console.log("导览已结束或被关闭");
  },
  steps: [
    {
      element: "#create-project",
      popover: {
        title: "创建项目",
        description: "从这里开始创建项目。",
      },
    },
  ],
});

不同 hooks 的参数会随触发时机不同而变化。实际编码时建议参考编辑器类型提示和官方 API 文档。

上报导览完成

js
const TOUR_KEY = "dashboard-tour-shown";

const driverObj = driver({
  onDestroyed: () => {
    localStorage.setItem(TOUR_KEY, "1");
    analytics.track("dashboard_tour_closed");
  },
  steps: tourSteps,
});

如果要区分“看完”和“中途关闭”,可以结合当前步骤索引判断。

js
const driverObj = driver({
  onDestroyed: () => {
    const state = driverObj.getState();
    const completed = state.activeIndex === tourSteps.length - 1;

    analytics.track("dashboard_tour_end", {
      completed,
      activeIndex: state.activeIndex,
    });
  },
  steps: tourSteps,
});

自定义下一步行为

有时下一步之前要先展开菜单、切换标签页或保存状态。可以在按钮 hook 中接管默认行为:

js
const driverObj = driver({
  steps: [
    {
      element: "#settings-button",
      popover: {
        title: "打开设置",
        description: "先打开设置面板,再查看下一步。",
        onNextClick: async () => {
          await openSettingsPanel();
          driverObj.moveNext();
        },
      },
    },
    {
      element: "#settings-panel",
      popover: {
        title: "设置面板",
        description: "这里可以调整团队偏好。",
      },
    },
  ],
});

如果接管了按钮行为,需要自己调用 moveNext()movePrevious(),否则引导不会继续。

按步骤设置 hooks

除了全局 hooks,也可以在某个 step 上设置局部逻辑:

js
const driverObj = driver({
  steps: [
    {
      element: "#advanced-menu",
      onHighlightStarted: () => {
        document.querySelector("#sidebar").classList.add("expanded");
      },
      popover: {
        title: "高级菜单",
        description: "展开后可以看到更多配置项。",
      },
    },
  ],
});

局部 hooks 适合处理某一步特有的 DOM 状态。

清理副作用

如果 hook 中修改了页面状态,记得在导览结束时恢复:

js
const sidebar = document.querySelector("#sidebar");

const driverObj = driver({
  onDestroyed: () => {
    sidebar?.classList.remove("expanded");
  },
  steps: [
    {
      element: "#advanced-menu",
      onHighlightStarted: () => {
        sidebar?.classList.add("expanded");
      },
      popover: {
        title: "高级菜单",
        description: "这里包含更多配置项。",
      },
    },
  ],
});

Hooks 很强,但不要把复杂业务流程都塞进导览。导览应该说明界面,而不是替代界面本身。