头图

vue项目中使用shepherd.js实现新手引导功能

小编因为需求的需要,所以找到了对应的新手指引解决方法,本篇文章记录下来,防止以后忘记小编还有去重新重头看文档

背景(为什么要实现和为什么选shepherd.js)

在现在的产品功能中,为了让使用用户快速了解并使用产品,节省用户的学习与使用文本,新手引导提示成为了常见的选择之一。这不人在公司坐,需求就来了,要弄一个新用户指引为用户,快速了解业务。

小编的需求类似于蓝湖的新用户指引差不多,不过小编的要加一个蒙版层不高亮其他部分,这里小编就以蓝湖的为例子教大家怎么去实现,(主要是记录好方便自己以后不用去查找文档)如下图所示:

小编开始想的是手撕一个,但是没有太多时间,肯定是处理不好对应的逻辑,到时候弄出来肯定是一改再改的,还不如用人家已迭代成熟的,手撕的想法就被小编给否决了。

就这样小编就开始了收罗之旅,小编在网上找了几个比较热门的,小编就放在下一个章节挨个介绍优缺点和小编为什么不用的原因。

热点插件库优缺点

vue-tour

vue-tour官网介绍中我们可以知道,其是一个轻量级、简单、可定制的游览插件。

优点:

  • 支持 Vue.js 指令使用和实例化调用,仅限 Vue.js 中可用
  • 比较轻巧,风格简洁
  • 支持自定义扩展功能

缺点:

  • 不支持黑色遮罩层,不支持高亮目标元素
  • 还需要额外的在 template 里面引用标签

小编的需求就是有黑色遮罩层,和目标元素高亮,这里刚开始小编还不知道,就这样糊里糊涂的用了,然后查找文档,才发现不知道。被迫无奈的弃用了,这里大家看好自己的需求,不适用就不用尝试这个了。

driver.js

Driver.js是一个可以轻松实现新手指引交互的JavaScript工具库

优点:

  • 无依赖,安装包很小,压缩完 4KB
  • 文档简洁又不缺功能,实例化调用,不局限是 Vue 还是 React 框架

缺点:

  • driver.js 实现方式属于是,修改父级的 z-index 层级实现遮罩,这样会有一个致命问题:当作用的新手引导元素父级存在定位是 fixed 的情况时,目标元素的层级始终无法超过白色高亮遮罩层。

小编这个也下载来用了一下,其实这个是没啥问题的,可能是小编没过多了解过,样式什么的也特别难改的样子,加上小编知道了他的缺点,和有些人说的一些什么在elementui弹窗上也会有一些问题,为了避免不必要的麻烦出现,小编就放弃了使用这个的想法。当然这只是小编的一面之词,大家可以自己去尝试一下。

Intro.js

Intro.js是一个轻量级的JavaScript库,用于创建逐步和强大的客户入门指南

优点:

  • 不需要其他任何依赖项。
  • 文件体积小,引导过程流畅。其中,JavaScript文件的整体大小为10KB, CSS为2.5KB。
  • 提供了多个主题,可根据个人喜好选择使用。
  • 兼容所有主流的浏览器,包括:Chrome、Firefox、Opera、Safari和IE浏览器。
  • 文档中包含了要介绍的每个元素的内容及示例。

缺点:

  • 非商用免费,商用要钱

这个也是网上很多人推荐的,也有很多例子什么的,就当小编要决定用他的时候,查看了开源协议,好家伙商用不免费,这本就不符合小编的原则,'为公司省大钱'。就果断放弃了

shepherd.js

shepherd.js 引导你的用户浏览你的应用。

优点:

  • API 众多,功能强大,多种场景都可以通过提供的 API 配置出来
  • API的自定义程度比较高

缺点:

  • 依赖popper.js包比较大

这不,小编看了大佬的博文推荐之后,立马就知道就是他了。那么让我们开启shepherd.js的神奇之旅吧。

shepherd.js的使用

安装

这里我们只写一种安装方法,其他的大家可以去官方文档查看

npm install shepherd.js --save

引入并使用

考虑到可能不是一个地方用到了,直接封装成一个通用的,一种直接挂载到vue原型链上,还有一种就是封装成组件,也就是一个方法来使用,这里我们就封装成组件来用

  • 在公共组件components文件夹里新建一个shepherd文件夹,在文件夹里新建一个js文件,这里小编命名为index.js 和新建一个css文件,由于小编用了sass 所以新建一个index.scss

    js模块代码如下:

    import Shepherd from 'shepherd.js'
    
    import './index.scss'
    
    // 定义一个统一的参数,因为是同一个系统的基本上都差不多一样的,不一样就通过函数参数去覆盖
    const defaultConfig = {
        // 是否显示黑色遮罩层
      useModalOverlay: true,
      // 键盘按钮控制步骤
      keyboardNavigation: false,
      // 这里是创建了一个默认的 导航组件
      defaultStepOptions: {
        classes: 'shepherd-theme-arrows', // 可以自定义类名,方便调整一些样式什么的不会影响到其他的
        // 显示关闭按钮
        cancelIcon: {
          enabled: false,
        },
        scrollTo: { behavior: 'smooth', block: 'center' },
        // 高亮元素四周要填充的空白像素
        modalOverlayOpeningPadding: 8,
        // 空白像素的圆角
        modalOverlayOpeningRadius: 4,
        buttons: [{  // 定义的按钮
          action () {
            return this.back()
          },
          text: '上一步'
        }, {
          action () {
            return this.next()
          },
          text: '下一步'
        }]
      }
    }
    // 通过函数的形式使用
    const shepherd = (props = {}) => {
      const newProps = {
           ...defaultConfig,
        ...props
      }
      return new Shepherd.Tour(newProps)
    }
    
    export {
      shepherd
    }

CSS文件内容如下:

@import '~shepherd.js/dist/css/shepherd.css';

// 这里可以写对对应的css进行修改,下面案例会补充

在目标页面写入以下代码

<template>
  <div>
    <div class="dimo" id="dimo-item">我是演示</div>
  </div>
</template>

<script>
import { shepherd } from "../../components/shepherd/index.js";

export default {
  name: "Dashboard",
  data() {
    return {
      shepherd: null,
    };
  },
  mounted() {
    this.initTour();
  },
  methods: {
    initTour() {
      this.shepherd = shepherd({});
      // 添加步骤
      this.shepherd.addSteps([
        {
          attachTo: {
            element: document.querySelector("#dimo-item"), // 目标元素
            on: "auto", // 指导窗的位置,auto 会自动计算
          },
          title: "顶部导航", // 标题
          text: "测试专用", // 内容
          buttons: [
            {
              action() {
                return this.cancel(); // 点击按钮的事件,这里的this就是当前的shepherd实例
              },
              text: "完成",
            },
          ],
        },
      ]);
      this.shepherd.start(); // 启动新手指引,如果不想一开始就启动就不用写在和初始化同一个函数里
    },
  },
};
</script>

<style lang="scss" scoped>
.dimo {
  width: 200px;
  height: 80px;
  background-color: aqua;
}
</style>

运行后如图下图所示我们就可以看到一个原生的新手指引了

案例演示

如上图所示,我们就以实现一个类似的来探索shepherd.js的更多属性

  1. 修改弹窗的颜色

    对比原图我们知道,我们的原生元素和我们要实现的样式还是有天差地别的,所以我们要了解一下这个指引窗的样式构成,这里直接打开f12开发者模式自己去看,如下图所示,这里不做过多的怎么去查看了,直接上代码。

// 加两个可以更好的避免样式污染,通过看文档和对应样式,我
// 我们可以看出指引窗有四个方向,我们需要那个方向的就改变那个方向的样式,这里就用方向的
@import '~shepherd.js/dist/css/shepherd.css';

.shepherd-has-title.shepherd-element {
  background-color: #158dff;
  &[data-popper-placement="bottom"] {
    margin-top: 60px !important;
  }
  &[data-popper-placement="left"] {
    margin-right: 60px !important;
  }
  &[data-popper-placement="right"] { // 这里专门改对应方向的样式
    margin-left: 60px !important;
    .shepherd-arrow {
      width: 60px;
      height: 1px;
      background-color: #158dff;
      left: -60px;
      &::before {
        display: none;
      }
    }
  }
  &[data-popper-placement="top"] {
    margin-bottom: 60px !important;
  }

  // 下面这些统一修改
  .shepherd-header {
    height: 40px;
    line-height: 40px;
    background-color: #158dff;
    .shepherd-title {
      font-size: 16px;
      font-weight: bold;
      color: #fff;
    }
  }
  .shepherd-text {
    font-size: 14px;
    padding: 1em;
    line-height: 1.6;
    color: #fff;
  }
  .shepherd-footer {
    padding: 0 1em 1em;
    color: #fff;
    .shepherd-button {
      height: 32px;
      padding: 0 1.5rem;
      line-height: 32px;
      background-color: #fff;
      color: #158dff;
      font-size: 14px;
    }
  }
}

这样之后我们就可以看到效果变成了下面这样,小效果就不调整了,看大家需求自己调整

  1. 设置显示步骤条

    这个小编以为也是API直接配置就行了,结果不是。在小编的不懈努力下,终于在官方文档找到了关于设置这个的,如下图:

我们可以看到他直接是利用现有的API结合js原生来进行的,这里一些解释小编直接放在代码里面了

initTour() {
      // 这里要注意,在shepherd里面的所以this的指向的是实例,我们要用外面的this就得如下处理
      let _that = this;
      _that.shepherd = shepherd({});
      // 添加步骤
      _that.shepherd.addSteps([
        {
          attachTo: {
            element: document.querySelector("#dimo-item"), // 目标元素
            on: "auto", // 指导窗的位置,auto 会自动计算
          },
          title: "顶部导航", // 标题
          text: "测试专用", // 内容
          buttons: [
            {
              action() {
                return this.cancel(); // 点击按钮的事件,这里的this就是当前的shepherd实例
              },
              text: "完成",
            },
          ],
          when: {
            // 相当于要执行的方法
            show() {
              // 执行的show方法
              const currentStep = _that.shepherd.getCurrentStep(); // 获取步骤窗口的整体
              const currentStepElement = currentStep.getElement(); // 获取步骤窗口的元素
              const footer = currentStepElement.querySelector(".shepherd-footer"); // 获取尾部部元素
              const progress = document.createElement("span");
              progress.style["margin-right"] = "237px"; // 这里我们也可以直接改造.shepherd-footer的布局
              progress.innerText = `${
                _that.shepherd.steps.indexOf(currentStep) + 1
              }/${_that.shepherd.steps.length}`;
              footer.insertBefore(
                progress,
                currentStepElement.querySelector(".shepherd-button ")
              ); // 往那个DOM元素插入前面一个DOM元素
            },
          },
        },
      ]);
      this.shepherd.start(); // 启动新手指引,如果不想一开始就启动就不用写在和初始化同一个函数里
    },

在对方法进行改造之后,我们可以看到以下效果:

我们的步骤条就完成了,当然我们也可以利用这个来实现不同的效果出来,这就是shepherd.js的高度自定义

  1. 全部代码

    小编经过细微调整后放出全部的代码

    • js

      /*
       * @Author: keqx
       * @Date: 2024-12-08 21:59:40
       * @LastEditors: keqx
       * @LastEditTime: 2024-12-09 01:14:16
       * @FilePath: \vue-admin-template\src\components\shepherd\index.js
       * @Description:
       *
       * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
       */
      import Shepherd from "shepherd.js";
      
      import "./index.scss";
      
      // 定义一个统一的参数,因为是同一个系统的基本上都差不多一样的,不一样就通过函数参数去覆盖
      const defaultConfig = {
        // 是否显示黑色遮罩层
        useModalOverlay: true,
        // 键盘按钮控制步骤
        keyboardNavigation: false,
        // 这里是创建了一个默认的 导航组件
        defaultStepOptions: {
          classes: "shepherd-theme-arrows", // 可以自定义类名,方便调整一些样式什么的不会影响到其他的
          // 显示关闭按钮
          cancelIcon: {
            enabled: false,
          },
          scrollTo: { behavior: "smooth", block: "center" },
          // 高亮元素四周要填充的空白像素
          modalOverlayOpeningPadding: 0,
          // 空白像素的圆角
          modalOverlayOpeningRadius: 4,
        },
      };
      // 通过函数的形式使用
      const shepherd = (props = {}) => {
        const newProps = {
          ...defaultConfig,
          ...props,
        };
        return new Shepherd.Tour(newProps);
      };
      
      export { shepherd };
      
  • css

    
    @import '~shepherd.js/dist/css/shepherd.css';
    
    .shepherd-has-title.shepherd-element {
      background-color: #158dff;
      &[data-popper-placement="bottom"] {
        margin-top: 60px !important;
      }
      &[data-popper-placement="left"] {
        margin-right: 60px !important;
      }
      &[data-popper-placement="right"] { // 这里专门改对应方向的样式
        margin-left: 60px !important;
        .shepherd-arrow {
          width: 60px;
          height: 1px;
          background-color: #158dff;
          left: -60px;
          &::before {
            display: none;
          }
        }
      }
      &[data-popper-placement="top"] {
        margin-bottom: 60px !important;
      }
    
      // 下面这些统一修改
      .shepherd-header {
        height: 40px;
        line-height: 40px;
        background-color: #158dff;
        .shepherd-title {
          font-size: 16px;
          font-weight: bold;
          color: #fff;
        }
      }
      .shepherd-text {
        font-size: 14px;
        padding: 1em;
        line-height: 1.6;
        color: #fff;
      }
      .shepherd-footer {
        padding: 0 1em 1em;
        color: #fff;
        .shepherd-button {
          height: 32px;
          padding: 0 1.5rem;
          line-height: 32px;
          background-color: #fff;
          color: #158dff;
          font-size: 14px;
        }
      }
    }
  • vue

    <template>
      <div>
        <div class="dimo" id="dimo-item">我是演示</div>
      </div>
    </template>
    
    <script>
    import { shepherd } from "../../components/shepherd/index.js";
    
    export default {
      name: "Dashboard",
      data() {
        return {
          shepherd: null,
        };
      },
      mounted() {
        this.initTour();
      },
      methods: {
        initTour() {
          // 这里要注意,在shepherd里面的所以this的指向的是实例,我们要用外面的this就得如下处理
          let _that = this;
          _that.shepherd = shepherd({});
          // 添加步骤
          _that.shepherd.addSteps([
            {
              highlightClass: "highlighted-border", // 为高亮元素添加额外的类名
              attachTo: {
                element: document.querySelector("#dimo-item"), // 目标元素
                on: "auto", // 指导窗的位置,auto 会自动计算
              },
              title: "顶部导航", // 标题
              text: "测试专用", // 内容
              buttons: [
                {
                  action() {
                    return this.cancel(); // 点击按钮的事件,这里的this就是当前的shepherd实例
                  },
                  text: "完成",
                },
              ],
              when: {
                // 相当于要执行的方法
                show() {
                  // 执行的show方法
                  const currentStep = _that.shepherd.getCurrentStep(); // 获取步骤窗口的整体
                  const currentStepElement = currentStep.getElement(); // 获取步骤窗口的元素
                  const footer =
                    currentStepElement.querySelector(".shepherd-footer"); // 获取尾部部元素
                  const progress = document.createElement("span");
                  progress.style["margin-right"] = "237px"; // 这里我们也可以直接改造.shepherd-footer的布局
                  progress.innerText = `${
                    _that.shepherd.steps.indexOf(currentStep) + 1
                  }/${_that.shepherd.steps.length}`;
                  footer.insertBefore(
                    progress,
                    currentStepElement.querySelector(".shepherd-button ")
                  ); // 往那个DOM元素插入前面一个DOM元素
                },
              },
            },
          ]);
          this.shepherd.start(); // 启动新手指引,如果不想一开始就启动就不用写在和初始化同一个函数里
        },
      },
    };
    </script>
    
    <style lang="scss" scoped>
    .dimo {
      width: 200px;
      height: 80px;
      background-color: aqua;
    }
    dialog {
      border: none;
    }
    .highlighted-border { // 高亮组件的额外样式
      border: 1px solid #158dff !important;
    }
    </style>
    

shepherd.js 属性方法汇总说明

这里小编以后用到其他的会更新到上面去

// 官方文档地址: https://docs.shepherdjs.dev/api/step/classes/step/#getelement

// 属性

useModalOverlay: boolean // 是否显示黑色遮罩层

keyboardNavigation: boolean // 键盘按钮控制步骤

defaultStepOptions: object // 默认选项,这里可以通过addSteps来设置,不过我们可以设置一些公共通用默认的,这里设置的如果addSteps有设置的话,addSteps的会覆盖这里的

 -- 子选的方法,这里的属性在addSteps方法里面配置的每一步里面配置都是一样的
 classes: string // 可以自定义类名,方便调整一些样式什么的不会影响到其他的
 highlightClass: string // 高亮元素的类名
 scrollTo: object // 高亮元素滚动到指定位置的配置
 modalOverlayOpeningPadding: number // 高亮元素四周要填充的空白像素
 modalOverlayOpeningRadius: number // 空白像素的圆角
 cancelIcon: object // 显示关闭按钮的配置
 cancelIcon: {
  enabled: boolean // 是否显示关闭按钮
 }

 attachTo: object // 高亮元素的定位配置
 attachTo: {
  element: document.querySelector("#XXX") // 目标元素,这里可以获取ID也可以用类名来
  on: string // 目标元素的定位方式,可以是 top, bottom, left, right, auto自动
 }

 title: string // 步骤的标题
 text: string // 步骤的描述
 buttons: array // 步骤的按钮配置
  buttons: [
    {
    text: string // 按钮的文本
    action: function // 按钮的点击事件
    }
  ]

  when: object //可以在里面定义show、hide、等一些事件方法


// 方法,注意这些方法在不同的配置里面有可能会不同作用大家详细的去查看官网文档

addSteps() // 设置对应步骤
cancel() // 触发取消事件
next() // 下一步事件
back() // 上一步事件
hide() // 隐藏当前步骤
isOpen() // 检查步骤是否是打开可见的
on(eventName, handler) // 监听事件 例如on(‘show’, function(){}) 监听show事件触发
show() // 显示的时候触发的事件 ,要保证其在beforeShowPromise之后触发
start() // 开始引导

getCurrentStep() // 获取当前步骤
getElement() // 获取当前步骤的元素

参考

新手引导组件我为什么选 shepherd.js?


一柯白菜
16 声望0 粉丝

坚持,热爱