npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sv-print/plugin-driver

v0.1.0

Published

sv-print plugin: driver 引导

Readme

@sv-print/plugin-driver

sv-print 的 设计器新手引导插件。基于 Driver.js 在设计器挂载后弹出一组引导气泡,引导用户熟悉界面布局与功能入口。

  • 通过 config.steps 完全数据化地描述引导流程
  • 首次挂载自动开启;后续按 cacheKey 跳过,可主动 resetGuide 重置
  • 步骤既可是静态对象,也可是返回 DriveStep 的函数(支持 Promise),便于在引导前通过 DOM 动态定位目标
  • 通过 sv-print 自带的 preferenceslocalStorage)持久化"已引导过"标记
  • designerUtils 上挂载运行时 API,便于在任意位置触发/重置引导

特性

  • 通过参数形式动态设置引导流程
  • 支持 cacheKey 版本号管理:升级引导内容时改 key 即可重新触达老用户
  • 步骤支持静态 DriveStep 也支持函数形式(可异步查询 DOM)
  • 自动跟随 onDesigned 钩子触发;可通过 autoStart: false 关闭
  • 内置 onDoneClick / onCloseClick 包装,自动写入"已完成"缓存并在适当时机清理 driver 实例
  • 暴露 designerUtils.startGuide(force?) / designerUtils.resetGuide() / designerUtils.getGuideCacheKey() 三个 API
  • 引导过程支持 driverOptions 透传 Driver.js 全局配置(按钮文案、进度、动画等)
  • 自带 driver.js 的样式资源,可通过 @sv-print/plugin-driver/dist/style.css 一键导入

安装

npm install @sv-print/plugin-driver
# 或
pnpm add @sv-print/plugin-driver

要求 sv-print >= 0.2.0

使用

sv-print 插件引入的两种方式见:sv-print 插件文档

记得先导入 driver.js 的样式:

import "@sv-print/plugin-driver/dist/style.css";
import pluginDriver from "@sv-print/plugin-driver";

const plugins = [
  pluginDriver({
    // 缓存 key,用于判断某个版本的 steps 是否需要执行
    cacheKey: "driver:DesignGuidance-v1",
    // 是否自动开启引导(默认 true)
    autoStart: true,
    // 引导步骤
    steps: [
      {
        element: ".svp-header",
        popover: { title: "这是菜单栏", description: "菜单栏支持插槽,也可以完全自定义" },
      },
      {
        element: ".svp-header .children .svp-flex:first-child",
        popover: { title: "左侧标题区域", description: "组件可以传递参数展示不同内容" },
      },
      {
        element: () => {
          // 也支持函数式 element,可结合页面状态动态定位
          const previewBox = document.querySelector(".previewBox");
          return previewBox?.closest(".svp-modal-box");
        },
        onHighlightStarted: () => {
          // 高亮开始时主动打开预览弹窗,便于引导用户
          onPreviewClick();
        },
        onDeselected: () => {
          designerUtils.preview.hide();
        },
        popover: {
          title: "这是预览弹窗",
          description: "可以浏览器打印、静默打印、导出图片、导出 pdf",
        },
      },
    ],
    // driver 选项(透传给 driver.js 的 Config)
    driverOptions: {
      showProgress: true,
      nextBtnText: "下一步",
      prevBtnText: "上一步",
      doneBtnText: "我知道了",
    },
    // 引导走完回调
    onComplete: () => {
      console.log("onboarded");
    },
    // 用户中途关闭 / 跳过时回调
    onSkip: () => {
      console.log("onSkip");
    },
  }),
];

在线 demo 示例代码

import "@sv-print/plugin-driver/dist/style.css";
import pluginDriver from "@sv-print/plugin-driver";
// 重置滚动条位置:driver.js 执行时会居中显示。执行完后重置滚动条,避免样式错乱。
const restScroll = () => {
  globalThis.$(`#paperBox`).scrollTop(0);
  globalThis.$(`.svp-designer`).scrollTop(0);
  globalThis.$(`#SVPrint`).scrollTop(0);
};
const plugins = [
  pluginDriver({
    // 缓存key,判断某个版本的 steps 是否需要执行
    cacheKey: "driver:DesignGuidance-v1",
    // 引导步骤
    steps: [
      {
        element: ".svp-header",
        popover: { title: "这是菜单栏", description: "这个菜单栏支持插槽,也可以完全自定义哟!" },
      },
      {
        element: ".svp-header .children .svp-flex:first-child",
        popover: {
          title: "左侧标题区域",
          description: "组件可以传递参数展示不同内容",
        },
      },
      {
        element: ".svp-header .children .svp-flex:nth-child(2)",
        popover: {
          title: "中间元素区域",
          description: "可通过 eleList 配置添加元素列表。reEle:true 则完全自定义。",
        },
      },
      {
        element: ".svp-header .children .svp-flex:last-child",
        popover: {
          title: "右侧菜单列表区域",
          description: "可通过 menuList 配置添加菜单列表。reMenu:true 则完全自定义。",
        },
      },
      {
        element: ".svp-header .children .svp-flex:last-child > div:nth-last-child(3) .children",
        onHighlightStarted: () => {
          globalThis
            .$(".svp-header .children .svp-flex:last-child > div:nth-last-child(3) .children")
            .css({ visibility: "visible", "z-index": "666" });
        },
        onDeselected: () => {
          globalThis
            .$(".svp-header .children .svp-flex:last-child > div:nth-last-child(3) .children")
            .css({ visibility: "", "z-index": "" });
        },
        popover: {
          title: "这是保存菜单中的子菜单",
          description:
            "子菜单可以自定义的。<br/>其中<span style='color:red;'>编辑模板数据、编辑打印数据、编辑拖拽元素</span> 是需要 <span style='color:#3c0aa8;'>编辑器插件(有官方插件,或自定义)<span style='color:red;'> 的哟!",
        },
      },
      {
        element: ".svp-header .children .svp-flex:last-child .svp-header-menu:nth-last-child(2)",
        popover: {
          title: "预览按钮",
          description:
            "点击可预览当前模板。记得要设置 printData 参数。 预览,打印,导出都需要它关联数据的。",
        },
      },
      {
        element: () => {
          const previewBox = document.querySelector(".previewBox");
          const targetParent = previewBox.closest(".svp-modal-box");
          return targetParent;
        },
        onHighlightStarted: () => {
          console.log("onHighlightStarted");
          onPreviewClick();
        },
        onDeselected: () => {
          console.log("onDeselected");
          designerUtilsIns.preview.hide();
        },
        popover: {
          title: "这是预览弹窗",
          description:
            "这个组件可以在非设计器中使用,顶部支持插槽。可以浏览器打印、静默打印、导出图片、导出pdf。",
        },
      },
      {
        element: ".toolbar",
        popover: {
          title: "这是工具栏",
          description:
            "选中元素可进行 对齐,字体调整,复制,删除等操作。左侧的设置按钮可自定义显示,排序。",
        },
      },
      {
        element: ".toolbar .right",
        popover: {
          title: "右侧工具栏",
          description: "显示/隐藏悬浮拖拽盒子。同时还有主题,语言的设置。",
        },
      },
      {
        element: "#dragBox-draggableEls",
        popover: {
          title: "拖拽元素列表",
          side: "right",
          description:
            "可拖拽的元素列表,可以通过provider自定义配置。当然样式也是可以自定义的。 拖拽到中间画布即可添加元素。<br/> <span style='color:#3c0aa8;'>同时这也是一个拖拽盒子。可以拖拽调整位置,大小。参数可控制起始位置。</span>",
        },
      },
      {
        element: "#dragBox-draggableEls .sv-edit",
        popover: {
          title: "编辑元素json",
          side: "right",
          description: "可拖拽的元素列表数据。可以通过provider自定义配置。可导入导出。",
        },
      },
      {
        element: "#printTemplate",
        onDeselected: () => {
          restScroll();
        },
        disableActiveInteraction: true,
        popover: {
          title: "这是面板(画布)编辑区域",
          description: "可拖拽元素到画布即可添加元素。点击元素查看属性。点击空白查看面板属性。",
        },
      },
      {
        element: () => {
          const list = Array.from(
            document.querySelectorAll(".hiprint-printElement-text-content")
          ).filter((el) => el.textContent.includes("sv-print"));
          if (list.length === 0) return null;
          const targetParent = list[0].closest(".hiprint-printElement");
          return targetParent;
        },
        onDeselected: () => {
          restScroll();
        },
        popover: {
          title: "这是面板(画布)中的打印元素",
          description:
            "点击元素可查看打印元素的属性。<br/>文本元素可以双击编辑内容。<br/>右键元素有菜单。<br/><span style='color:#3c0aa8;'>设计好样式后可以保存为自定义元素。然后可以导出,方便后续使用。</span>",
        },
      },
      {
        element: "#printTemplate .hiprint-headerLine",
        onDeselected: () => {
          restScroll();
        },
        popover: {
          title: "这个是页眉线",
          description: "可从顶部拖拽出来(面板属性也有)。页眉线之上的内容,每页显示。",
        },
      },
      {
        element: "#printTemplate .hiprint-footerLine",
        onDeselected: () => {
          restScroll();
        },
        popover: {
          title: "这个是页脚线",
          description: "可从底部拖拽出来(面板属性也有)。页脚线下的内容,每页显示。",
        },
      },
      {
        element: "#dragBox-panels .body",
        popover: {
          title: "多面板操作区域",
          description: "一个模板可以有多个面板,每个面板可以有多个元素。面板",
        },
      },
      {
        element: "#dragBox-options",
        popover: {
          title: "属性区域",
          side: "left",
          description: "点击面板(画布)空白,可查看面板的属性。点击元素,可查看元素的属性。",
        },
      },
      {
        element: "#dragBox-pageStructure",
        popover: {
          title: "页面结构区域",
          side: "left",
          description: "鼠标悬停在某个位置,可查看当前元素在面板的哪个位置。",
        },
      },
      {
        element: "#dragBox-history",
        popover: {
          title: "历史记录区域",
          side: "left",
          description: "记录部分操作的历史记录。点击可回退到某一步操作。",
        },
      },
      {
        element: "#dragBox-miniMap",
        popover: {
          title: "概览图区域",
          side: "right",
          description: "当前画布/面板的概览图。可以拖拽,方向键调整画布显示区域。",
        },
      },
    ],
    autoStart: true, // 是否自动开启引导,默认 true
    // driver 选项
    driverOptions: {
      showProgress: true,
      nextBtnText: "下一步",
      prevBtnText: "上一步",
      doneBtnText: "我知道了",
    },
    // 引导完成回调
    onComplete: () => {
      restScroll();
      console.log("onboarded");
    },
    // 引导跳过回调
    onSkip: () => {
      restScroll();
      console.log("onSkip");
    },
  }),
];

配置项

type PluginConfig = {
  /** 引导步骤,支持静态 DriveStep 或返回 DriveStep 的函数(可异步) */
  steps?: GuideStep[];
  /** 写入 sv-print preferences 的 key,默认 plugin-driver:default */
  cacheKey?: string;
  /** 透传给 driver.js 的全局配置,如按钮文案、动画等 */
  driverOptions?: Partial<driver.Config>;
  /** 设计器挂载后是否自动开启引导,默认 true */
  autoStart?: boolean;
  /** 引导走完最后一步时回调 */
  onComplete?: () => void;
  /** 用户中途关闭 / 跳过时回调 */
  onSkip?: () => void;
};

GuideStep 类型:

type GuideStep = DriveStep | (() => DriveStep | Promise<DriveStep>);

可直接复用 driver.js 的 DriveStep 所有能力:元素定位、onHighlightStarted / onDeselected 等生命周期钩子、popover.title / description / side / align 等气泡外观。

运行时 API

插件在挂载时会把以下方法挂到 designerUtils 上,业务代码可以在任意位置调用:

| 方法 | 说明 | | ---------------------------------- | -------------------------------------------------------------------- | | designerUtils.startGuide(force?) | 立即开启引导;force=true 时忽略已读缓存强制开启 | | designerUtils.resetGuide() | 清除已读标记并立刻开启引导,等价于 startGuide(true) + clearCache | | designerUtils.getGuideCacheKey() | 取得当前插件所使用的缓存 key |

// 例如:用户点击"再看一次引导"按钮
button.onclick = () => designerUtils.resetGuide?.();

缓存机制

  • 写入位置:sv-print 的 preferences store(底层是 localStorage 上的 sv-print-preferences
  • 写入时机:用户走完最后一步点击 Done 时
  • 跳过时机:用户点击关闭按钮或遮罩时不会写入缓存,下次挂载会自动重新开启
  • 主动重置:designerUtils.resetGuide()setPreferences("driver:DesignGuidance-v1", false)

升级引导文案 / 增减步骤时,建议同步更新 cacheKey 的版本号(如 v1v2),否则老用户无法感知到新版引导。

License

MIT

开源使用须知

  1. 请自觉遵守 MIT 协议,其他用途可联系作者;
  2. 允许用于个人学习、毕业设计、教学案例、公益事业、商业使用;
  3. 商用请仔细审查代码和漏洞,不得用于任一国家许可范围之外的商业应用,产生的一切任何后果责任自负;