Skip to content

引导效果 driver.js 封装使用

shell
pnpm add driver.js
查看封装代码
ts
import { driver as createDriver, type Config, type DriveStep } from 'driver.js'
import 'driver.js/dist/driver.css'
import { onUnmounted } from 'vue'
// 配置文档看 https://driverjs.com/docs/configuration
// driver 是单例模式

export function useStepDriver(option: Config) {
  const driver = createDriver()
  const showDriver = () => {
    driver.setConfig({
      nextBtnText: '下一步',
      prevBtnText: '上一步',
      doneBtnText: '完成',
      allowClose: false, // 空白处不让关闭
      smoothScroll: false,
      ...option
    })
    driver.drive()
  }
  onUnmounted(() => {
    driver.destroy()
  })
  return { showDriver, driver }
}

export function useSingleDriver(step: DriveStep) {
  const driver = createDriver()
  const showDriver = () => {
    driver.setConfig({ allowClose: true })
    driver.highlight({
      ...step
    })
  }
  onUnmounted(() => {
    driver.destroy()
  })
  return { showDriver, driver }
}

基础用法

欲买桂花同载酒,终不似,少年游。
晓看天色暮看云,行也思君,坐也思君。
欲买桂花同载酒,终不似,少年游。
查看代码
vue
<template>
  <div class="base-demo">
    <a-divider> 简单示例 只显示一个 </a-divider>
    <a-button type="primary" @click="showBaseDriver">show</a-button>
  </div>

  <div class="step-demo">
    <a-divider> 步骤示例 显示几个步骤 </a-divider>
    <div class="step-demo-container">
      <div class="p">欲买桂花同载酒,终不似,少年游。</div>
      <div class="p">晓看天色暮看云,行也思君,坐也思君。</div>
    </div>
    <a-button type="primary" @click="showStepDriver">show</a-button>
  </div>

  <div class="async-demo">
    <a-divider> 异步渲染示例 </a-divider>
    <div class="async-demo-container">
      <div class="p">欲买桂花同载酒,终不似,少年游。</div>
      <div class="p" v-if="asyncShow">晓看天色暮看云,行也思君,坐也思君。</div>
    </div>
    <a-button type="primary" @click="showAsyncDriver">show</a-button>
  </div>
</template>
<script lang="ts" setup>
import { nextTick, ref } from 'vue'
import { useSingleDriver, useStepDriver } from './driver'

const { showDriver: showBaseDriver } = useSingleDriver({
  element: '.base-demo',
  popover: {
    title: '简单示例的标题',
    description: '我来实现一个简单示例的引导程序'
  }
})

const { showDriver: showStepDriver } = useStepDriver({
  steps: [
    { element: '.step-demo', popover: { title: '步骤1', description: '整个大块' } },
    { element: '.step-demo-container', popover: { title: '步骤2', description: '内部div' } },
    {
      element: '.step-demo-container > .p:nth-child(1)',
      popover: { title: '步骤3', description: '第一段' }
    },
    {
      element: '.step-demo-container > .p:nth-child(2)',
      popover: { title: '步骤4', description: '第二段' }
    }
  ]
})

const asyncShow = ref(false)
const { showDriver: showAsyncDriver, driver: asyncDriver } = useStepDriver({
  steps: [
    { element: '.async-demo', popover: { title: '步骤1', description: '内部div' } },
    {
      element: '.async-demo-container > .p:nth-child(1)',
      popover: {
        title: '步骤2',
        description: '第一段',
        onNextClick() {
          asyncShow.value = true
          nextTick(() => asyncDriver.moveNext())
        }
      }
    },
    {
      element: '.async-demo-container > .p:nth-child(2)',
      popover: { title: '步骤3', description: '某种情况下的第二段' },
      onDeselected() {
        asyncShow.value = false
      }
    }
  ]
})
</script>
<style scoped>
.step-demo-container > .p,
.async-demo-container > .p {
  margin-bottom: 16px;
}
</style>

自定义

1
第一步
2
第二步
3
第三步
查看代码
vue
<template>
  <div class="custom-demo">
    <a-divider> 自定义示例 </a-divider>
    <div class="step-container">
      <Steps :current="state.current" :items="state.steps" />
      <div style="margin: 16px 0">
        <p class="step-content-1" v-if="state.current === 1">第一步的内容</p>
        <p class="step-content-2" v-if="state.current === 2">第二步的内容</p>
        <p class="step-content-3" v-if="state.current === 3">第三步的内容</p>
      </div>
    </div>
    <a-button type="primary" @click="openDriver">show</a-button>
  </div>
</template>

<script setup lang="ts">
import { Steps } from 'ant-design-vue'
import type { Config } from 'driver.js'
import { nextTick, reactive } from 'vue'
import { useStepDriver } from './driver'

const state = reactive({
  current: 0,
  steps: [{ title: '第一步' }, { title: '第二步' }, { title: '第三步' }]
})

const driverOption = reactive({
  steps: [
    {
      element: '.step-container',
      popover: { title: '步骤1', description: '第一步是为了xxx' }
    },
    {
      element: '.step-container',
      popover: { title: '步骤2', description: '第二步是为了xxx' }
    },
    {
      element: '.step-container',
      popover: { title: '步骤3', description: '第三步是为了xxx' }
    }
  ],
  onNextClick() {
    if (driver.isLastStep()) {
      state.current = 0
      driver.destroy()
      return
    }
    state.current++
    console.log(' onNextClick state.current ', state.current)
    nextTick(() => driver.moveNext())
  },
  onPrevClick() {
    state.current--
    console.log(' onPrevClick state.current ', state.current)
    nextTick(() => driver.movePrevious())
  },
  onCloseClick() {
    state.current = 0
    driver.destroy()
  }
}) as Config

const { showDriver, driver } = useStepDriver(driverOption)

function openDriver() {
  state.current = 1
  nextTick(() => showDriver())
}
</script>

<style scoped>
.custom-demo {
  .a-button {
    margin-top: 16px;
  }
}
</style>