el-tour微探:优雅实现新手引导功能

  • 作者简介:大家好,我是文艺理科生Owen,某车企前端开发,负责AIGC+RAG项目
  • 目前在卷的技术方向:工程化系列,主要偏向最佳实践
  • 希望可以在评论区交流互动,感谢支持~~~

最近公司项目新增了新手引导的需求,由于项目中使用了element-plus组件库, el-tour 组件肯定是首选。神贴中大部分是在讲vue-tour,几乎没有el-tour的身影。所以决定分享一下。
先看一下最终的效果~

%E5%AA%92%E4%BD%931_converted.gif

只实现这个需求的话确实不难,价值在于实现需求的整个分析过程。一般在需求实现前,我通常会多想一步,或许这就是天然的代码洁癖吧。主要有两点思考:

  • 新增代码必然会耦合到现有的业务逻辑中,但新手引导只是一个独立的功能,增加了原业务代码的复杂度
  • 新手引导会与需求迭代保持同步,如何提高代码的可维护性,进而实现快速迭代

说明:el-tour组件的关键是目标对象的关联

设计方案

基于上述思考点,有了一个初步的设计结构图:

image.png

简单来说,将引导说明文案单独保存在一个配置文件中,并引入到每个页面的公共引导组件中

这里我们将通过一个demo来举例说明。

最佳实践demo实现

  1. 快速生成项目:pnpm create vite vue3-pdf-demo --template vue
  2. 运行:
    cd vue3-pdf-demo
    pnpm install
    pnpm run dev
  3. 项目启动成功后,安装 element plus组件库,pnpm i element-plus,此处的版本是2.7.2
  4. 安装完成后,复制下面代码,引入和注册组件库。
// 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')
  1. 在App.vue中新建一些元素,效果图和代码如下:

image.png

// 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>
  1. 封装公共引导组件,命名为 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>

说明:

  1. 当前步为开始语时,不展示目标对象,只是居中展示,需要将target设置为undefined;
  2. el-tour跳过按钮(可以用关闭按钮替代,只是这里有特殊要求),需要自行实现。可以使用indicators插槽,将元素样式设置为 flex 布局右对齐。由于el-tour的父元素为body,

image.png

所有此处样式需要在 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' // 自定义的样式文件
  1. 下一步按钮名称修改需要注意。当时项目中尝试了好多方法,都无法实现修改。翻了下issue,找到了 #15637#15680。所以第一反应是赶紧升级。当时默认安装的版本是2.5.2,需要指定版本才能升到2.7.2。这次复盘制作demo时默认安装的版本已经是2.7.2了,所以有问题的话留意下版本号。
  1. 创建引导文案配置文件,命名为 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框架"
    }
  ]
}
  1. 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

  1. 最终效果图:
    %E5%AA%92%E4%BD%931_converted.gif

总结:本文采用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

日拱一卒,功不唐捐。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值