vue3封装el-tour漫游式引导

vue3使用el-tour漫游式引导组件封装

我们这里先看下运行效果:

预览效果

引入的第三方库方法我这里就不写了,可以自行去官网查找。

我们看一下组件封装的部分。

tourPage.vue
html 复制代码
  <el-tour v-model="open" :show-close="false" @change="onStepChange" :content-style="{
      width: '80%',
      fontSize: '16px',
      color: '#252525',
    }">
      <el-tour-step v-for="(item, index) in data" :key="index" :target="item.target" :title="item.title ? item.title : `第${currentStep}步`" :description="item.description" :prev-button-props="{
        children: '上一步',
        onClick: handlePrevClick
      }" :next-button-props="{
        children: nextBtnName,
        onClick: handleNextClick
      }" />
      <template #indicators="{ current, total }">
        <span style="font-size: 16px; color: #252525;">{{ current + 1 }} / {{ total }}</span>
      </template>
    <!--   <template #indicators>
        <el-button size="small" @click="handleSkip">跳过</el-button>
      </template> -->
    </el-tour>

数据结构:

ts 复制代码
const tourData = computed(() => [
  {
    title: "功能引导",
    description: "让我们来学习一下",
  },
  {
    title: "功能按钮",
    description: "这里有每日一言和票房大全功能入口",
    target: () => ref1.value,
  },
  {
    title: "个人中心",
    description: "点击头像可以打开个人中心,更换头像和昵称,还可以和机器人对话",
    target: () => ref2.value,
  },
  {
    title: "新年彩蛋",
    description: "一会可以点击这里,看看有什么惊喜",
    target: () => ref3.value,
  },
  {
    title: "关于文案",
    description: "表面可以查看文案,从这里点击进入可以开启音乐",
    target: () => ref4?.value?.$el || null
  },
  {
    title: "抽奖",
    description: "点击这里可以进入抽奖页面,试试手气吧",
    target: () => ref5.value,
  },
]);

这里需要注意一下第四个部分,我这里因为要直接绑定第三方组件Vant的van-notice-bar的所以需要使用Vant中自带的NoticeBarInstance 类型

js 复制代码
import type { NoticeBarInstance } from 'vant';

所以在定义的时候需要这么写

js 复制代码
const ref4 = ref<NoticeBarInstance>()          // 文案通知栏
// 数据
target: () => ref4?.value?.$el || null

如果是引导饿了么的组件获取dom类型可以从官网上查看,比如绑定在el-button按钮上

ts 复制代码
import type { ButtonInstance } from 'element-plus'
const ref4 = ref<ButtonInstance>()   
// 数据
{
    title: "关于文案",
    description: "表面可以查看文案,从这里点击进入可以开启音乐",
    target: () => ref4?.value?.$el || null
},

如果不用官网的方法也可以直接使用js方法获取,当然你也不需要NoticeBarInstance 类型了

js 复制代码
const ref4 = ref<HTMLElement | null>(null)
// 数据
{
    title: "关于文案",
    description: "表面可以查看文案,从这里点击进入可以开启音乐",
    target: () => document.querySelector('.van-notice-bar'),
},

自定义按钮文字

html 复制代码
      <el-tour-step
        v-for="(item, index) in data"
        :key="index"
        :target="item.target"
        :title="item.title ? item.title : `第${currentStep}步`"
        :description="item.description"
        :prev-button-props="{
          children: '上一步',
          onClick: handlePrevClick
        }"
        :next-button-props="{
          children: nextBtnName,
          onClick: handleNextClick
        }"
      />

组件完整代码:

html 复制代码
<script setup lang="ts">
import { ref, computed, PropType } from "vue";
import type { ButtonInstance } from 'element-plus'
import type { NoticeBarInstance } from 'vant';
// 引导步骤项目接口定义
interface TourItem {
  title: string;                   // 步骤标题
  description: string;             // 步骤描述
  target?: () => NoticeBarInstance | HTMLElement | null | undefined | any;  // 目标元素
}
// Props 定义
const props = defineProps({
  data: {
    type: Array as PropType<TourItem[]>,
    required: true
  },
  modelValue: {
    type: Boolean,
    default: false
  }
})

// 事件发射器
const emits = defineEmits(['change', 'prev', 'next', 'update:modelValue'])

// 引导组件显示状态(双向绑定)
const open = computed({
  get: () => props.modelValue,
  set: (value) => emits('update:modelValue', value)
})

// 当前引导步骤
const currentStep = ref(0);

// 下一步按钮文本
const nextBtnName = computed(() => {
  let name = ''
  if (!currentStep.value) {
    name = '开始'
  } else if (currentStep.value === props.data.length - 1) {
    name = '完成'
  } else {
    name = `下一步(${currentStep.value} / ${props.data.length - 1})`
  }
  return name
})

// 步骤变化处理函数
const onStepChange = (step: number) => {
  currentStep.value = step
  emits('change', step)
}

// 跳过按钮处理函数(暂未启用)
/* const handleSkip = () => {
  open.value = false
} */

// 上一步按钮处理函数
const handlePrevClick = () => {
  emits('prev', currentStep.value)
}

// 下一步按钮处理函数
const handleNextClick = () => {
  emits('next', currentStep.value)
}
</script>

<template>
  <div>
    <el-tour v-model="open" :show-close="false" @change="onStepChange" :content-style="{
      width: '80%',
      fontSize: '16px',
      color: '#252525',
    }">
      <el-tour-step
        v-for="(item, index) in data"
        :key="index"
        :target="item.target"
        :title="item.title ? item.title : `第${currentStep}步`"
        :description="item.description"
        :prev-button-props="{
          children: '上一步',
          onClick: handlePrevClick
        }"
        :next-button-props="{
          children: nextBtnName,
          onClick: handleNextClick
        }"
      />
      <template #indicators="{ current, total }">
        <span style="font-size: 16px; color: #252525;">{{ current + 1 }} / {{ total }}</span>
      </template>
      <!-- 跳过按钮(暂未启用) -->
      <!-- <template #indicators>
        <el-button size="small" @click="handleSkip">跳过</el-button>
      </template> -->
    </el-tour>
  </div>
</template>

<style scoped></style>

这里的记步条可以用插槽indicators去做,详细的写法看上述代码即可

最后在父组件使用:

html 复制代码
    <TourPage
      v-model="tourVisible"
      :data="tourData"
      @change="(step) => console.log('当前步骤:', step)"
      @prev="(step) => console.log('上一步:', step)"
      @next="(step) => console.log('下一步:', step)"
    />
    <el-button color="#626aef" @click="startTour">
      快速引导
    </el-button>
js 复制代码
const tourVisible = ref(false)
// 点击时开启
const startTour = () => {
  tourVisible.value = true
}

数据附下

js 复制代码
// 引导步骤配置
const tourData = computed(() => [
  {
    title: "功能引导",
    description: "让我们来学习一下",
  },
  {
    title: "功能按钮",
    description: "这里有每日一言和票房大全功能入口",
    target: () => ref1.value,
  },
  {
    title: "个人中心",
    description: "点击头像可以打开个人中心,更换头像和昵称,还可以和机器人对话",
    target: () => ref2.value,
  },
  {
    title: "新年彩蛋",
    description: "一会可以点击这里,看看有什么惊喜",
    target: () => ref3.value,
  },
  {
    title: "关于文案",
    description: "表面可以查看文案,从这里点击进入可以开启音乐",
    target: () => ref4?.value?.$el || null
  },
  {
    title: "抽奖",
    description: "点击这里可以进入抽奖页面,试试手气吧",
    target: () => ref5.value,
  },
]);
相关推荐
℡52Hz★21 分钟前
Three.js+Vue3+Vite应用lil-GUI调试开发3D效果(三)
开发语言·前端·javascript·3d
kelly072140 分钟前
移动端H5缓存问题
前端·缓存
小白也想学C1 小时前
ubuntu22.04:解决google chrome 访问百度页面加载慢的问题
前端·chrome
关山月2 小时前
使用 Tailwind CSS 和 JavaScript 构建延迟加载图片
前端
天若有情6732 小时前
想法分享,利用html通过求输入框中用户输入数组的最大值
前端·html
风无雨2 小时前
2025真实面试题
前端·面试
鲤鱼池2 小时前
Vue3: 二次封装组件的原则与方法
前端·面试
垃圾侠2 小时前
vue2版本tinymce简单使用指南
前端·vue.js
LLLuckyGirl~2 小时前
vite功能之---npm 依赖解析和预构建
前端·npm·node.js
Cygra2 小时前
Next.js + Mediapipe 手势识别画板:前端玩转机器学习
前端·人工智能·机器学习