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,
  },
]);
相关推荐
anyup_前端梦工厂2 小时前
了解几个 HTML 标签属性,实现优化页面加载性能
前端·html
前端御书房3 小时前
前端PDF转图片技术调研实战指南:从踩坑到高可用方案的深度解析
前端·javascript
2301_789169543 小时前
angular中使用animation.css实现翻转展示卡片正反两面效果
前端·css·angular.js
风口上的猪20154 小时前
thingboard告警信息格式美化
java·服务器·前端
程序员黄同学4 小时前
请谈谈 Vue 中的响应式原理,如何实现?
前端·javascript·vue.js
爱编程的小庄5 小时前
web网络安全:SQL 注入攻击
前端·sql·web安全
爱学习的小王!5 小时前
nvm安装、管理node多版本以及配置环境变量【保姆级教程】
经验分享·笔记·node.js·vue
宁波阿成5 小时前
vue3里组件的v-model:value与v-model的区别
前端·javascript·vue.js
柯腾啊5 小时前
VSCode 中使用 Snippets 设置常用代码块
开发语言·前端·javascript·ide·vscode·编辑器·代码片段
weixin_535854225 小时前
oppo,汤臣倍健,康冠科技,高途教育25届春招内推
c语言·前端·嵌入式硬件·硬件工程·求职招聘