- 作者简介:大家好,我是文艺理科生Owen,某车企前端开发,负责AIGC+RAG项目
- 目前在卷的技术方向:工程化系列,主要偏向最佳实践
- 希望可以在评论区交流互动,感谢支持~~~
最近公司项目新增了新手引导
的需求,由于项目中使用了element-plus组件库, el-tour
组件肯定是首选。神贴中大部分是在讲vue-tour
,几乎没有el-tour
的身影。所以决定分享一下。
先看一下最终的效果~
只实现这个需求的话确实不难,价值在于实现需求的整个分析过程。一般在需求实现前,我通常会多想一步,或许这就是天然的代码洁癖吧。主要有两点思考:
- 新增代码必然会耦合到现有的业务逻辑中,但新手引导只是一个独立的功能,增加了原业务代码的复杂度
- 新手引导会与需求迭代保持同步,如何提高代码的可维护性,进而实现快速迭代
说明:el-tour组件的关键是目标对象的关联
设计方案
基于上述思考点,有了一个初步的设计结构图:
简单来说,将引导说明文案单独保存在一个配置文件中,并引入到每个页面的公共引导组件中。
这里我们将通过一个demo来举例说明。
最佳实践demo实现
- 快速生成项目:
pnpm create vite vue3-pdf-demo --template vue
- 运行:
cd vue3-pdf-demo
pnpm install
pnpm run dev
- 项目启动成功后,安装 element plus组件库,
pnpm i element-plus
,此处的版本是2.7.2 - 安装完成后,复制下面代码,引入和注册组件库。
// main.js
import {
createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
- 在App.vue中新建一些元素,效果图和代码如下:
// App.vue
<template>
<div class="container">
<!-- 页面元素 -->
<button id="guideRef1" class="html-button">html</button>
<button id="guideRef2" class="css-button">css</button>
<button id="guideRef3" class="js-button">javascript</button>
<button id="guideRef4" class="mvvm-button">vue/react</button>
</div>
</template>
<style scoped>
.container {
position: relative;
}
.container>button {
position: absolute;
width: 200px;
height: 50px;
}
.html-button {
top: 200px;
left: 200px;
background-color: burlywood;
}
.css-button {
top: 400px;
left: 400px;
background-color: olivedrab;
}
.js-button {
top: 600px;
left: 600px;
background-color: yellow;
}
.mvvm-button {
top: 300px;
left: 1000px;
background-color: greenyellow;
}
</style>
- 封装公共引导组件,命名为
Guide.vue
。代码如下:
// Guide.vue
<template>
<div>
<el-tour
v-model="open"
:show-close="false"
@change="handleChange"
>
<el-tour-step
v-for="(item, index) in props.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>
<el-button size="small" @click="handleSkip">跳过</el-button>
</template>
</el-tour>
</div>
</template>
<script setup>
import {
ref, computed } from "vue";
const props = defineProps(['data'])
const emits = defineEmits(['change', 'prev', 'next'])
// 引导组件开启状态
const open = ref(true);
// 当前步数,从0开始,由于第0步是开始语,后面的步数可以正好对应
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 handleChange = (step) => {
currentStep.value = step
emits('change')
}
// 点击跳过按钮时触发
const handleSkip = () => {
open.value = false
}
// 点击上一步按钮时触发
const handlePrevClick = () => {
emits('prev')
}
// 点击下一步按钮时触发
const handleNextClick = () => {
emits('next')
}
</script>
说明:
- 当前步为开始语时,不展示目标对象,只是居中展示,需要将target设置为undefined;
el-tour
无跳过
按钮(可以用关闭按钮替代,只是这里有特殊要求),需要自行实现。可以使用indicators
插槽,将元素样式设置为 flex 布局右对齐。由于el-tour的父元素为body,
所有此处样式需要在 main.js 中全局覆盖。具体如下:
- 在
assets
目录下新建index.css
,样式代码如下:
// assets/index.css
.el-tour__content .el-tour-indicators {
display: flex;
justify-content: flex-end;
margin-right: 5px;
}
在
main.js
中覆盖 element ui 的css样式文件。
// main.js
import 'element-plus/dist/index.css' // element的默认样式文件
import './assets/index.css' // 自定义的样式文件
- 创建引导文案配置文件,命名为
guide.json
。代码如下:
// config/guide.json
{
"guideOptions": [
{
"title": "欢迎来到AI前端训练营",
"description": "点击开始一起进入快乐的学习之旅吧"
},
{
"target": "#guideRef1",
"title": "",
"description": "学习html"
},
{
"target": "#guideRef2",
"title": "",
"description": "学习css"
},
{
"target": "#guideRef3",
"title": "",
"description": "学习js"
},
{
"target": "#guideRef4",
"title": "",
"description": "学习MVVM框架"
}
]
}
- 在
App.vue
中引用Guide
组件,并导入配置数据进行关联。
// App.vue
<template>
<div class="container">
// ...其他代码
<!-- 引导组件 -->
<Guide v-model="open" :data="guideOptions" />
</div>
</template>
<script setup>
import Guide from './components/Guide.vue'
import {
guideOptions } from './config/guide.json'
// 声明操作指引开启状态(为了演示方便,默认开启)
const open = defineModel({
default: true
});
</script>
由于引导组件的开关状态变量为双向绑定,直接使用v-model传值会简单一些,vue3.4新增的传值功能,记得面试时卷一下。相关链接:组件 v-model
- 最终效果图:
总结:本文采用
element plus
组件库中的el-tour
组件实现了用户引导功能,通过代码拆分结构设计,保证了引导文案
、公共引导组件
、页面组件
之间的低耦合性、可维护性、高复用性,并针对过程中遇到的问题和解决方法进行了说明。
参考文献:
1.element plus:el-tour组件
demo源代码:
github V7.0.1
r组件实现了用户引导功能,通过代码拆分结构设计,保证了
引导文案、
公共引导组件、
页面组件`之间的低耦合性、可维护性、高复用性,并针对过程中遇到的问题和解决方法进行了说明。
参考文献:
1.element plus:el-tour组件
demo源代码:
github V7.0.1
日拱一卒,功不唐捐。