Skip to content

driver.js 引导插件

  • 简单:简单易用,完全没有外部依赖
  • 高度可定制:有一个强大的api,可以用于你希望突出显示任何内容
  • 高亮显示:页面功能介绍上的任意元素(字面上的任意)
  • 功能介绍:为你的web应用程序创建强大的功能介绍
  • 焦点移位器:为用户友好添加焦点移位器
  • 用户友好:通过键盘行为控制一切
  • 一致行为:所有浏览器(包括著名的IE)都可以使用
  • MIT声明:免费用于个人和商业用途。
  • 安装
bash
npm install driver.js

基本使用

  • 引入插件
js
import Driver from "driver.js";
import "driver.js/dist/driver.min.css";

插件选项

Driver 选项

js
const driver = new Driver({
  className: 'scoped-class', //包裹driver.js弹窗的类名 className to wrap driver.js popover
  animate: true,  // 高亮元素改变时是否显示动画 Animate while changing highlighted element
  opacity: 0.75,  //背景透明度(0 表示只有弹窗并且没有遮罩) Background opacity (0 means only popovers and without overlay)
  padding: 10,   //  元素与边缘的距离 Distance of element from around the edges
  allowClose: true, // 是否允许点击遮罩时关闭 Whether clicking on overlay should close or not
  overlayClickNext: false, //是否允许点击遮罩时移到到下一步 Should it move to next step on overlay click
  doneBtnText: 'Done', // 最终按钮上的文本 Text on the final button
  closeBtnText: 'Close', // 当前步骤关闭按钮上的文本 Text on the close button for this step
  nextBtnText: 'Next', //当前步骤下一步按钮上的文本 Next button text for this step
  prevBtnText: 'Previous', // 当前步骤上一步按钮上的文本 Previous button text for this step
  showButtons: false, //是否在底部显示控制按钮 Do not show control buttons in footer
  keyboardControl: true, // 是否允许通告键盘控制(escape关闭,箭头键用于移动)Allow controlling through keyboard (escape to close, arrow keys to move)
  scrollIntoViewOptions: {}, //  `scrollIntoView()` 方法的选项 We use `scrollIntoView()` when possible, pass here the options for it if you want any
  onHighlightStarted: (Element) {}, // 元素开将要高亮时调用Called when element is about to be highlighted
  onHighlighted: (Element) {}, // 元素开完全高亮时调用Called when element is fully highlighted
  onDeselected: (Element) {}, // 取消选择时调用 Called when element has been deselected
  onReset: (Element) {},        // 遮罩将要关闭时调用 Called when overlay is about to be cleared
  onNext: (Element) => {},      // 任何步骤中移到到下一步时调用Called when moving to next step on any step
  onPrevious: (Element) => {},  // 任何步骤中移到到上一步时调用Called when moving to next step on any step
});

step 选项

js
const stepDefinition = {
  element : '#some-item' ,         // 查询要突出显示的选择器字符串或节点
  stageBackground : '#ffffff' ,    // 这将覆盖驱动程序中设置的
  popover : {                     // 不会有 popover如果为空或未给定
    className : 'popover-class' ,  // 除了驱动程序选项中的一般 className 之外,还要包装此特定步骤 popover 的 className
    title : 'Title' ,              // 弹出框上的标题
    description : 'Description' , // 弹出框的主体
    showButtons : false ,          // 不要在页脚中显示控制按钮
    doneBtnText : 'Done' ,         // 最后一个按钮上的文本
    closeBtnText : 'Close' ,       // 关闭按钮上的文本
    nextBtnText : 'Next' ,         // 下一个按钮文本
    prevBtnText : 'Previous' ,     // 上一个按钮文本
  } ,
  onNext : ( )  =>  { } ,              // 从当前步骤移动到下一步时调用
  onPrevious :( )  =>  { } ,          // 从当前步骤移动到上一步时调用
} ;

API方法

js
const driver = new Driver(driverOptions);

const isActivated = driver.isActivated; // 检查driver是否激活Checks if the driver is active or not
driver.moveNext();     // 移动到步骤列表中的下一步 Moves to next step in the steps list
driver.movePrevious(); // 移动到步骤列表中的上一步 Moves to previous step in the steps list
driver.start(stepNumber = 0);  // 从指定的步骤开始 Starts driving through the defined steps
driver.highlight(string|stepDefinition); // 高亮通过查询选择器指定的或步骤定义的元素 highlights the element using query selector or the step definition
driver.reset(); // 重置遮罩并且清屏Resets the overlay and clears the screen
driver.hasHighlightedElement(); //检查是否有高亮元素 Checks if there is any highlighted element
driver.hasNextStep(); // 检查是否有可移动到的下一步元素 Checks if there is next step to move to
driver.hasPreviousStep(); // 检查是否有可移动到的上一步元素。Checks if there is previous step to move to

driver.preventMove();// 阻止当前移动。如果要执行某些异步任务并手动移动到下一步,则在“onNext”或“onPrevious”中很有用 Prevents the current move. Useful in `onNext` or `onPrevious` if you want to
// perform some asynchronous task and manually move to next step



const activeElement = driver.getHighlightedElement();// 获取屏幕上当前高亮元素 Gets the currently highlighted element on screen
const lastActiveElement = driver.getLastHighlightedElement();
activeElement.getCalculatedPosition(); // 获取活动元素的屏幕坐标Gets screen co-ordinates of the active element
activeElement.hidePopover();  // 隐藏弹窗Hide the popover
activeElement.showPopover();  // 显示弹窗Show the popover

activeElement.getNode();  // 获取此元素后面的DOM元素Gets the DOM Element behind this element
你可以使用各种各样的选项来实现你想要的一切。You can use a variety of options to achieve whatever you may want.

Demo 实例

vue
<template>
  <div class="space-y-2">
    <div>
      <el-button id="step1">第一步元素</el-button>
      <el-button id="step2">第二步元素</el-button>
      <template v-if="dySteps && dySteps.length > 0">
        <el-button v-for="(item, i) in dySteps" :key="item.id" :id="item.id">
          {{ `动态元素 第${i + 1}步元素` }}
        </el-button>
      </template>
      <el-button id="step4">高亮元素</el-button>
    </div>
    <div>
      <el-button @click="startGuide">开始引导</el-button>
      <el-button @click="addNewStep">动态添加步骤</el-button>
      <el-button @click="safeHighlight('#step4')">高亮 Step4</el-button>
    </div>
    <div><hight></hight></div>
  </div>
</template>

<script>
import Driver from "driver.js";
import "driver.js/dist/driver.min.css";
import hight from "./hight.vue";

export default {
  components: {
    hight,
  },
  data() {
    return {
      dySteps: [],
      isNew: false,
      driver: null,
      steps: [
        {
          element: "#step1",
          popover: {
            title: "步骤1",
            description: "这是第一个步骤",
            position: "bottom",
          },
        },
        {
          element: "#step2",
          popover: {
            title: "步骤2",
            description: "这是第一个步骤",
            position: "bottom",
          },
        },
      ],
    };
  },
  mounted() {
    // 初始化
    this.driver = new Driver({
      animate: true,
      opacity: 0.75,
      doneBtnText: "完成",
      closeBtnText: "关闭",
      nextBtnText: "下一步",
      prevBtnText: "上一步",
    });
  },
  methods: {
    safeHighlight(elementSelector, options = {}) {
      const element = document.querySelector(elementSelector);

      if (!element) {
        console.warn(`元素 ${elementSelector} 不存在`);
        return false;
      }

      // 确保元素可见
      element.scrollIntoView({ behavior: "smooth", block: "center" });

      const driverObj = new Driver();
      setTimeout(() => {}, 200);
      this.$nextTick(() => {
        setTimeout(() => {
          driverObj.highlight({
            element: elementSelector,
            popover: {
              title: "选择采样方法",
              description: "这里展示所有采样方法,点击即可选择",
              position: "bottom",
              // closeBtnText: '下一步',
            },
            animate: true,
            opacity: 0.75,
            doneBtnText: "完成",
            closeBtnText: "关闭",
            nextBtnText: "下一步",
            prevBtnText: "上一步",
            ...options,
          });
        }, 200);
      });

      return true;
    },
    // 开始引导
    startGuide() {
      console.log("---", this.driver);
      // this.driver.reset();
      console.log("==== this.steps: ", this.steps);
      this.driver.defineSteps(this.steps);
      setTimeout(() => {
        this.driver.start();
      }, 200);
    },

    // 动态"添加"步骤(实际是给数组 push,然后重新定义)
    addNewStep() {
      // 新增步骤到数组
      console.log("==== this.steps: ", this.steps);
      const id = "dy_" + new Date().getTime();
      this.dySteps.push({
        id,
        element: "#" + id,
        popover: {
          title: "步骤1",
          description: "这是第一个步骤",
          position: "bottom",
        },
      });
      this.steps = [...this.steps, ...this.dySteps];

      console.log("====  this.driver: ", this.driver);
      this.driver.reset();
      setTimeout(() => {
        console.log("==== this.steps: ", this.steps);
        // 如果引导正在进行中,需要重置并重新开始
        if (this.driver.isActivated) {
          const currentIndex = this.driver.getCurrentStep();
          this.driver.defineSteps(this.steps);
          // 恢复到之前的步骤位置
          this.driver.start(currentIndex);
        } else {
          this.driver.defineSteps(this.steps);
          this.driver.start();
        }
      }, 200);
    },
  },
};
</script>
<style lang="scss">
/* ####################  driver.js 按钮 转为 ElementUI风格 #################### */
div#driver-popover-item .driver-popover-footer {
  /* 2. 统一 Driver 所有按钮的基础样式(复用 ElementUI 按钮核心样式) */
  button {
    /* 复用 ElementUI 按钮基础样式:内边距、字体、边框、圆角等 */
    display: inline-block;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    background: #fff;
    border: 1px solid #dcdfe6;
    color: #606266;
    -webkit-appearance: none;
    text-align: center;
    box-sizing: border-box;
    outline: none;
    margin: 0;
    transition: 0.1s;
    padding: 6px 12px;
    font-size: 14px;
    border-radius: 4px;
    margin-right: 0px; /* 按钮之间间距 */
    font-weight: normal !important;
    text-shadow: none !important;
    &.driver-disabled {
      display: none !important;
    }

    /* 按钮悬浮效果(ElementUI 默认风格) */
    &:hover {
      color: #409eff;
      border-color: #c6e2ff;
      background-color: #ecf5ff;
    }

    /* 去除 Driver 默认的 active 样式(避免冲突) */
    &:active {
      box-shadow: none;
    }
  }

  /* 3. 「下一步/完成」按钮:ElementUI 主色调(primary) */
  .driver-next-btn,
  .driver-done-btn {
    background: #409eff;
    border-color: #409eff;
    color: #fff;

    &:hover {
      background: #66b1ff;
      border-color: #66b1ff;
      color: #fff;
    }
  }

  /* 4. 「跳过」按钮:ElementUI 警告色调(warning,可选) */
  .driver-close-btn {
    margin: 10px 0 10px;
    background: #e6a23c;
    border-color: #e6a23c;
    color: #fff;

    &:hover {
      background: #ebb563;
      border-color: #ebb563;
      color: #fff;
    }
  }

  /* 5. 「上一步」按钮:ElementUI 默认风格(可保持默认,或改为次要色调) */
  .driver-prev-btn {
    /* 保持基础样式,如需修改为次要色调,可添加如下样式:
    background: #f5f7fa;
    border-color: #e4e7ed;
    color: #303133;
    &:hover {
      background: #e9ecef;
      border-color: #dcdfe6;
      color: #303133;
    }
    */
  }

  /* 6. 优化按钮容器布局(让按钮排列更美观,贴合 ElementUI 风格) */
  .driver-btn-group {
    padding: 10px 0;
    text-align: right;
  }
}
</style>