从0到1开发一个Vue3的新手引导组件(附带遇到的问题以及解决方式)

1. 前言:

新手引导组件,顾名思义,就是强制性的要求第一次使用的用户跟随引导使用应用,可以让一些第一次使用系统的新手快速上手,正好我最近也遇到了这个需求,于是就想着开发一个通用组件拿出来使用(写完之后才发现element就有,后悔了哈哈哈😭😭)

示例图:

  1. 第一步
    第一步

  2. 第二步
    第二步

  3. 第三步
    第三步

2. 使用的技术栈以及组件:

Vue3+Vite+Element+uuid,使用了el-popover组件以及el-button组件

3. 遇到的问题:

开发这个组件不是一个简单的事情,遇到了不少的问题,尤其是样式上的问题,下面我一一说明以及对应的解决方式

  1. 需要将用户可以点击的部分凸出出来:

    在原先我是打算给组件传入一个class类名的,然后通过指定的class类名获取到dom,之后再通过dom.getBoundingclientRect()方法获取指定dom的尺寸以及位置信息,然后再组件中创建一个空白区域,但是我真正尝试的时候才发现一个致命问题,getBoundingclientRect方法获取的位置信息都是对的,但是尺寸却是固定的0,后面才发现,如果新手引导的内容是一个图片的话,就必须要等到图片加载完成后再在页面上进行引导,我尝试了onload之后再进行绘制,虽然实现了想要的效果,但是我觉得这样操作太麻烦了,就抛弃了这种方法

  2. 改为插槽:

    上面的方法行不通,操作也麻烦,然后我就创建了两个插槽,一个是content插槽,此插槽没有任何作用,只是将内容显示出来,一个是target插槽,这里的插槽将会作为新手引导的内容,这里解释下为什么需要两个插槽,因为新手引导组件可能应用于循环中,针对于循环的其他内容,可以使用content插槽填充,需要新手引导的内容再使用target插槽即可

4. 源码讲解(请查看详细注释):

<!--* @Author: wangZhiyu <w3209605851@163.com>* @Date: 2024-07-05 09:28:39* @LastEditTime: 2024-07-11 14:05:36* @LastEditors: wangZhiyu <w3209605851@163.com>* @Descripttion: /新手引导组件.vue
-->
<template><!-- 新手引导插槽 --><div class="targetSlot" v-if="isTarget"><!-- 提示文字区域 --><el-popover :popper-style="`width:auto;color:#000;font-size:20px;z-index:${forceShowPopover ? 9999 : 2024}`" :visible="visible" placement="top" :offset="25"><!-- popover内的元素 --><div style="white-space: nowrap; display: flex; align-items: center; justify-content: center"><el-button v-if="isShowAudioCourse" type="info" circle size="small" style="font-size: 18px">?</el-button><span style="margin: 0 5px">{{ tipMessage }}</span><el-button v-if="readBtn" type="primary" @click="onRead">{{ readMessage }}</el-button></div><!-- 触发popover的元素 --><template #reference><!-- 元素背景高亮区域 --><div :class="`highLightArea highLightArea_${uuid}`" v-if="isFoucsArea"></div></template></el-popover><slot name="target"></slot></div><!-- <slot name="target"></slot> --><!-- 普通内容插槽(根据传入的参数进行动态改变) --><slot :name="isTarget ? 'content' : 'target'"></slot><!-- 新手引导遮罩层(这里给遮罩层添加了一个点击事件,并且组织事件冒泡,是为了避免点击遮罩层所产生事件冒泡罩层影响) --><div class="maskArea" @click.stop="() => {}" v-if="isFoucsArea && value"></div>
</template><script setup>
// 导入UUID库
import { v4 as uuidv4 } from 'uuid';import { ref, nextTick, onMounted, useSlots, watch } from 'vue';// 设置是否显示提示信息
const visible = ref(false);// 生成一个uuid
const uuid = uuidv4();// 抛出事件
const emits = defineEmits(['onRead']);// 父组件传入的参数
const props = defineProps({// 是否继承父组件样式isInheritStyle: {type: Boolean,default: () => false,},// 高亮区域盒子的占比大小-->宽highLightAreaWidth: {type: [String, Number],},// 高亮区域盒子的占比大小-->高highLightAreaHeight: {type: [String, Number],},// 高亮区域盒子的占比位置-->垂直距离调整highLightAreaTop: {type: [String, Number],},// 高亮区域盒子的占比位置-->水平距离调整highLightAreaLeft: {type: [String, Number],},// 是否强制显示提示(避免提示被遮住的情况)forceShowPopover: {type: Boolean,default: () => false,},// 是否显示已阅读按钮readBtn: {type: Boolean,default: () => false,},// 内部按钮文字readMessage: {type: String,default: () => '下一步',},// 提示文字tipMessage: {type: String,default: () => '',},// 是否显示提示按钮,点击后可显示对应的视频教程isShowAudioCourse: {type: Boolean,default: () => false,},// 是否为当前应该显示的教程步骤(用于一个页面多个步骤的流程引导)isTarget: {type: Boolean,default: () => true,},// 是否为当前应该显示的教程步骤(用于一个页面多个步骤的流程引导)value: {type: Boolean,default: () => true,},
});// 当前组件中被使用的插槽
const slot = useSlots();// 已完成引导
const onRead = () => {visible.value = false;emits('onRead');
};// 是否聚焦按钮,高亮新手引导
let isFoucsArea = ref(false);// 如果 slot.target 成立,则表示使用了新手引导插槽
isFoucsArea.value = slot.target ? true : false;// 页面初始化函数
const init = () => {nextTick(() => {// 判断是否指定了新手引导插槽的高层级盒子继承父元素的全部css属性(最小程度的影响添加一个div布局的影响)if (props.isInheritStyle) {// 获取新手引导插槽的高层级盒子const targetSlot = document.querySelector('.targetSlot');targetSlot.className = 'inheritFather';}// 获取高亮盒子const highLightArea = document.querySelector(`.highLightArea_${uuid}`);// 判断高亮盒子是否存在if (highLightArea) {// 根据指定参数配置盒子的高亮区域尺寸highLightArea.style.width = `${props.highLightAreaWidth || 100}%`;highLightArea.style.height = `${props.highLightAreaHeight || 100}%`;highLightArea.style.top = `${props.highLightAreaTop || 50}%`;highLightArea.style.left = `${props.highLightAreaLeft || 50}%`;}// TODO:将显示提示放在setTimeout中,存入宏任务队列,避免顺序执行错误,应该等到highLightArea盒子全部处理完成后再显示提示区域,否则有可能显示的位置不对,这里设置是否显示提示信息表示为isFoucsArea.value,表示只给设置了新手引导插槽中添加提示,其余盒子不添加提示setTimeout(() => (visible.value = isFoucsArea.value), 100);});
};watch(() => props.isTarget,() => {setTimeout(() => {visible.value = true;}, 1);}
);onMounted(init);
</script><style>
.maskArea {position: fixed;top: 0px;left: 0px;width: 100vw;height: 100vh;background: rgba(0, 0, 0, 0.4);z-index: 1;cursor: default;
}
.handGif {position: absolute;left: 100%;width: 60px;height: 70px;transform: translateX(50%);
}.targetSlot {position: relative;z-index: 10;display: flex;justify-content: center;align-items: center;
}.inheritFather {all: inherit;z-index: 10;
}
.highLightArea {position: absolute;width: 100%;height: 100%;top: 50%;left: 50%;transform: translate(-50%, -50%);border: 3px solid #fff;border-radius: 5px;z-index: 9;font-size: 16px;pointer-events: none;padding: 10px;
}
</style>

5. 使用新手引导组件示例:

<!--* @Author: wangZhiyu <w3209605851@163.com>* @Date: 2024-07-09 13:44:13* @LastEditTime: 2024-07-09 15:49:38* @LastEditors: wangZhiyu <w3209605851@163.com>* @FilePath: \Vue3新手引导组件\Vue3-Tour\src\App.vue* @Descripttion: 
-->
<template><div class="container"><w-tour @onRead="onRead" readBtn tipMessage="这是新手教程的第一步" :isTarget="step === 1" :value="open"><template #target><el-button type="primary">按钮1</el-button></template></w-tour><w-tour @onRead="onRead" readBtn tipMessage="这是新手教程的第二步" :isTarget="step === 2" :value="open"><template #target><el-button type="primary">按钮2</el-button></template></w-tour><w-tour @onRead="onRead" readBtn tipMessage="这是新手教程的第三步" :isTarget="step === 3" :value="open"><template #target><el-button type="primary">按钮3</el-button></template></w-tour></div>
</template>
<script setup>
import { ref } from 'vue';
const step = ref(1);
const open = ref(true);const onRead = () => {step.value++;if (step.value === 4) {// step.value = 0;open.value = false;}console.log(step.value);
};
</script><style scoped>
.container {display: flex;justify-content: space-around;align-items: center;width: 500px;height: 100px;background-color: #7c7777;margin: 100px auto;padding: 10px;
}
</style>

6. 总结:

以上就是从0到1开发一个能简单使用的新手引导组件的全过程以及源码了,可能使用起来不是很方便,哈哈,这里不得不佩服那些开发通用组件的大佬,确实很不容易👍🏻👍🏻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/870357.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【芯片方案】珠宝手机秤方案

珠宝手机秤作为一种便携式电子称重设备&#xff0c;因其小巧、便携、精度高等特点&#xff0c;广泛应用于各种需要精确称重的场景。可能这个目前在国内使用的人比较少&#xff0c;但在西方国家珠宝手机秤却是可以用来送礼的物品。因为珠宝手机秤的外观跟手机外观大多相似&#…

顶顶通呼叫中心中间件-打电话没声音检查步骤(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-电话没声音检查步骤(mod_cti基于FreeSWITH) 检查步骤 1、检查配置文件 检查配置文件&#xff1a;打开ccadmin -> 配置文件 -> vars -> external_ip$${local_ip_v4}看一下这个有没有配置正确的外网IP&#xff0c;如果没有配置正确就需要配置正…

PyCharm 2023.3.2 关闭时一直显示正在关闭项目

文章目录 一、问题描述二、问题原因三、解决方法 一、问题描述 PyCharm 2023.3.2 关闭时一直显示正在关闭项目 二、问题原因 因为PyCharm还没有加载完索引导致的 三、解决方法 方法一&#xff1a; 先使用任务管理器强制关闭&#xff0c;下次关闭时注意要等待PyCharm加载完索…

C语言-顺序表

&#x1f3af;引言 欢迎来到HanLop博客的C语言数据结构初阶系列。在这个系列中&#xff0c;我们将深入探讨各种基本的数据结构和算法&#xff0c;帮助您打下坚实的编程基础。本次我将为你讲解。顺序表&#xff08;也称为数组&#xff09;是一种线性表&#xff0c;因其简单易用…

ArcGIS Pro入门制图教程

地理信息系统 (GIS) 是一种使用地图显示和分析数据的方式。在本教程中&#xff0c;您将学习桌面 GIS 应用程序 ArcGIS Pro 的基础知识。 新加坡的一家旅行社希望制作一款宣传册&#xff0c;用于向游客介绍距离市中心热门目的地最近的火车站。该宣传册将与带有文本信息的地图相…

使用 `useAppConfig` :轻松管理应用配置

title: 使用 useAppConfig &#xff1a;轻松管理应用配置 date: 2024/7/11 updated: 2024/7/11 author: cmdragon excerpt: 摘要&#xff1a;本文介绍了Nuxt开发中useAppConfig的使用&#xff0c;它便于访问和管理应用配置&#xff0c;支持动态加载资源、环境配置切换、权限…

软考:软件设计师 — 2.操作系统

二. 操作系统 1. 操作系统概念 &#xff08;1&#xff09;操作系统的作用 操作系统是计算机硬件之上的第一层软件系统。 操作系统通常用来&#xff1a; 管理系统的硬件、软件、数据资源。控制程序运行。人机之间的接口。应用软件与硬件之间的接口。 可概括为&#xff1a; …

【Linux】内核文件系统系统调用流程摸索

内核层可以看到当前调用文件处理的进程ID 这个数据结构是非常大的&#xff1a; 我们打印的pid,tgid就是从这里来的&#xff0c;然后只需要找到pid_t的数据类型就好了。 下图这是运行的日志信息&#xff1a; 从上述日志&#xff0c;其实我也把write的系统调用加了入口的打印信…

CSS3实现彩色变形爱心动画【附源码】

随着前端技术的发展&#xff0c;CSS3 为我们提供了丰富的动画效果&#xff0c;使得网页设计更加生动和有趣。今天&#xff0c;我们将探讨如何使用 CSS3 实现一个彩色变形爱心加载动画特效。这种动画不仅美观&#xff0c;而且可以应用于各种网页元素&#xff0c;比如加载指示器或…

水库大坝安全监测险情主要内容

水库常见险情主要包括洪水漫顶、脱坡滑坡、坝体裂缝、 散浸、渗漏、漏洞、陷坑、管涌等&#xff0c;此外风浪冲击、水流冲刷等也会加剧险情的扩大。大坝险情万一抢护不及时&#xff0c;易导致发 生溃坝事故&#xff0c;造成极为严重的灾难性后果。要做到及时有效地 抢护大坝险情…

科技信息项目验收测试包括哪些内容?验收测试报告如何获取?

科技信息项目验收测试是指在科技信息项目完成后&#xff0c;组织专业测评团队对项目开发过程和成果进行全面、系统、客观的评测和鉴定的过程。通过验收测试&#xff0c;可以评估项目的质量、功能完整性以及满足业务需求的程度&#xff0c;并为项目的成功上线提供依据。 为了进…

uniapp实现table排序

根据后端接口传来的数字大小对列表进行升序/降序展示 效果图&#xff0c;价格由高到低降序 价格由低到高 升序 js 降序升序代码如下 export default {data() {return {MtList:[]}},onLoad() {this.MtypeName();//加载列表方法},methods: {MtypeName(){//列表方法this.$api.…

与沃尔玛进行EDI对接,需要了解什么?如何实现EDI对接呢?

与沃尔玛进行EDI对接前&#xff0c;需要了解什么呢&#xff1f; 首先&#xff0c;需要了解什么是EDI&#xff1f; EDI&#xff08;Electronic Data Interchange&#xff09;即电子数据交换&#xff0c;借助EDI使得企业&#xff08;计算机/应用系统&#xff09;与企业&#xff…

2024透明加密软件最新推荐丨11款好用的透明加密软件

在数字化时代&#xff0c;文件与数据安全愈发重要&#xff0c;保护信息安全刻不容缓。文件加密软件应运而生&#xff0c;成为了信息安全的重要帮手。透明加密技术凭借众多的优点备受青睐。那么&#xff0c;什么是透明加密技术呢&#xff1f; 透明加密技术是一种在不影响用户正…

STM32读取LX-224总线舵机信息

一、舵机指令包格式 帧头&#xff1a; 连续收到两个 0x55 ,表示有数据包到达。ID: 每个舵机都有一个 ID 号。ID 号范围 0&#xff5e;253,转换为十六进制 0x00&#xff5e;0xFD。广播 ID: ID 号 254(0xFE) 为广播 ID,若控制器发出的 ID 号为 254(0xFE)&#xff0c;所有的舵机均…

『Django』自带的后台

theme: smartblue 本文简介 点赞 关注 收藏 学会了 上一篇讲了 Django 操作 MySQL 的方法&#xff0c;讲了如何创建模型&#xff0c;如何对数据库做增删改查的操作。但每次修改数据都要写代码&#xff0c;多少有点麻烦。 有没有简单一点的方法呢&#xff1f; 有的有的&#…

第十九章 Nest multer 文件上传

上章我们了解了Express multer 文件上传的相关操作 本章将了解Nest中的文件上传。用 multer 包处理 multipart/form-data 类型的请求中的 file 新建个 nest 项目: nest new nest-multer-upload 安装 multer 的 ts 类型的包&#xff1a; npm install -D types/multer1、单文件…

Linux C语言基础 day7

目录 思维导图&#xff1a; 学习目标&#xff1a; 学习内容&#xff1a; 1. 数组 1.1 对数组元素的常规操作 1.1.1 逆序 1.1.2 挑选数据 1.1.3 排序 1. 冒泡排序 2. 选择排序 2. 二维数组 2.1 二维数组的概念 2.1.1. 定义格式 2.2.2.初始化 2.2 二维数组的相关操…

2.4G芯片开发的遥控玩具方案介绍 东莞酷得

玩具从早期的简单功能&#xff0c;到现如今各种各样的智能操作&#xff0c;发展的速度也是飞速的。随着玩具市场的逐步完善与推进&#xff0c;中国的智能玩具市场也出现了很多远程遥控玩具。遥控玩具也是从最初的有线到现在的无线&#xff0c;从地上跑的到天上飞的&#xff0c;…

Wireshark 对 https 请求抓包并展示为明文

文章目录 1、目标2、环境准备3、Wireshark 基本使用4、操作步骤4.1、彻底关闭 Chrome 进程4.2、配置 SSLKEYLOGFILE [核心步骤]4.3、把文件路径配置到 Wireshark 指定位置4.4、在浏览器发起请求4.5、抓包配置4.6、过滤4.6.1、过滤域名 http.host contains "baidu.com4.6.2…