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,
  },
]);
相关推荐
满怀10157 分钟前
【Django全栈开发实战】从零构建企业级Web应用
前端·python·django·orm·web开发·前后端分离
Darling02zjh1 小时前
GUI图形化演示
前端
Channing Lewis1 小时前
如何判断一个网站后端是用什么语言写的
前端·数据库·python
互联网搬砖老肖1 小时前
Web 架构之状态码全解
前端·架构
showmethetime1 小时前
matlab提取脑电数据的五种频域特征指标数值
前端·人工智能·matlab
左钦杨3 小时前
IOS CSS3 right transformX 动画卡顿 回弹
前端·ios·css3
NaclarbCSDN3 小时前
Java集合框架
java·开发语言·前端
进取星辰3 小时前
28、动画魔法圣典:Framer Motion 时空奥义全解——React 19 交互动效
前端·react.js·交互
不爱吃饭爱吃菜4 小时前
uniapp微信小程序-长按按钮百度语音识别回显文字
前端·javascript·vue.js·百度·微信小程序·uni-app·语音识别
程序员拂雨5 小时前
Angular 知识框架
前端·javascript·angular.js