vue3封装el-tour漫游式引导
vue3使用el-tour漫游式引导组件封装
我们这里先看下运行效果:
预览效果
引入的第三方库方法我这里就不写了,可以自行去官网查找。
我们看一下组件封装的部分。
tourPage.vue
<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>
数据结构:
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
类型
import type { NoticeBarInstance } from 'vant';
所以在定义的时候需要这么写
const ref4 = ref<NoticeBarInstance>() // 文案通知栏
// 数据
target: () => ref4?.value?.$el || null
如果是引导饿了么的组件获取dom类型可以从官网上查看,比如绑定在el-button
按钮上
import type { ButtonInstance } from 'element-plus'
const ref4 = ref<ButtonInstance>()
// 数据
{
title: "关于文案",
description: "表面可以查看文案,从这里点击进入可以开启音乐",
target: () => ref4?.value?.$el || null
},
如果不用官网的方法也可以直接使用js方法获取,当然你也不需要NoticeBarInstance
类型了
const ref4 = ref<HTMLElement | null>(null)
// 数据
{
title: "关于文案",
description: "表面可以查看文案,从这里点击进入可以开启音乐",
target: () => document.querySelector('.van-notice-bar'),
},
自定义按钮文字
<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
}"
/>
组件完整代码:
<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
去做,详细的写法看上述代码即可
最后在父组件使用:
<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>
const tourVisible = ref(false)
// 点击时开启
const startTour = () => {
tourVisible.value = true
}
数据附下
// 引导步骤配置
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,
},
]);