当前位置: 首页 > news >正文

从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开发一个能简单使用的新手引导组件的全过程以及源码了,可能使用起来不是很方便,哈哈,这里不得不佩服那些开发通用组件的大佬,确实很不容易👍🏻👍🏻

相关文章:

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

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

概率统计(二)

二维离散型 联合分布律 样本总数为16是因为&#xff0c;两封信分别可以放在4个信箱 边缘分布律 条件分布律 独立性 选填才能用秒杀 联合概率乘积不等于边缘概率的乘积则不独立 二维连续型 区间用一重积分面积用二重积分 离散型随机变量 常见6个分布的期望和方差 离散型随机变…...

文件类:如何将excel文件转为csv文件(且保留时间格式)?

最近有个场景&#xff0c;在ftp服务器上&#xff0c;读取csv文件并入库&#xff0c;但是客户提供的一部分文件却是xls文件&#xff0c;就得搞个将excel转为csv文件的方法&#xff0c;话不多说直接开干。 方法 public static void convertExcelToCSV(String excelFilePath, Str…...

FiddlerScript Rules修改-更改发包中的cookie

直接在fiddler script editor中增加如下处理代码即可 推荐文档oSession -- 参数说明 测试笔记 看云...

直升机停机坪的H代表什么

可为什么直升机的停机坪为什么要用“H”来表示呢&#xff1f; Helicopter 直升机停机坪的“H”来自直升机的英文Helicopter的首字母&#xff0c;也是停机坪的识别标志&#xff0c;表示可用于直升机的垂直起降&#xff0c;方便于直升机飞行员在空中能快速识别降落位置。 另外…...

hyperworks软件许可优化解决方案

Hyperworks软件介绍 Altair 仿真驱动设计改变了产品开发&#xff0c;使工程师能够减少设计迭代和原型测试。提升科学计算能力扩大了应用分析的机会&#xff0c;使大型设计研究能够在限定的项目时间完成。现在&#xff0c;人工智能在工程领域的应用再次改变了产品开发。基于物理…...

四川赤橙宏海商务信息咨询有限公司抖音电商服务靠谱吗?

在数字化浪潮席卷全球的今天&#xff0c;电商行业蓬勃发展&#xff0c;各种新兴电商平台层出不穷。其中&#xff0c;抖音电商以其独特的社交属性和庞大的用户基础&#xff0c;迅速崛起为行业新星。四川赤橙宏海商务信息咨询有限公司&#xff0c;作为专注于抖音电商服务的佼佼者…...

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【密钥派生(C/C++)】

密钥派生(C/C) 以HKDF256密钥为例&#xff0c;完成密钥派生。具体的场景介绍及支持的算法规格&#xff0c;请参考[密钥生成支持的算法]。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生成密钥 指定密钥别名。 初始化密钥属…...

【ARMv8/v9 GIC 系列 6 -- 中断优先级详细介绍】

请阅读【ARM GICv3/v4 实战学习 】 文章目录 Interrupt prioritizationInterrupt Priority ValueSGI And PPI Priority SetSecure And Non-secure Priority AccessInterrupt prioritization 在ARM GICv3和GICv4架构中,中断的优先级化(prioritization)是通过以下几种方式来描…...

【CORS 报错】跨域请求问题:CORS 多种环境下的解决方案

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、CORS错误的常见原因二、解决方案1. Vue3 Vite项目下的解决方案创建Vue3 Vite项目配置Vite的代理发送请求 2. jQuery项目下的解决方案使用CORS请求头使用JSONP 3. 其他环境下的解决方案使用服务器端代理设置CORS头使用…...

【Scrapy】深入了解 Scrapy 中间件中的 process_spider_output 方法

准我快乐地重饰演某段美丽故事主人 饰演你旧年共寻梦的恋人 再去做没流着情泪的伊人 假装再有从前演过的戏份 重饰演某段美丽故事主人 饰演你旧年共寻梦的恋人 你纵是未明白仍夜深一人 穿起你那无言毛衣当跟你接近 &#x1f3b5; 陈慧娴《傻女》 Scrapy 是…...

GigE Vision GVCP/GVSP

GIGE协议&#xff0c;全称Gigabit Ethernet Vision协议&#xff0c;是一种基于千兆以太网&#xff08;Gigabit Ethernet&#xff09;技术开发的相机接口标准&#xff0c;主要用于高速图像采集和处理。该协议通过以太网技术实现图像数据和控制信号的传输&#xff0c;具有低成本、…...

结合C++智能指针聊聊观察者模式

0. 问题 问题是这样&#xff0c;三个类A,B,C。AC都有指针指向同一个B类对象&#xff0c;C类可以回收了刚刚生成的B类对象的内存&#xff0c;A类应该对这个指针进行如何操作&#xff0c;才能确保使用该指针时不会产生野指针问题发生未定义结果&#xff1f; 这是前两天面试的时候…...

【React】监听浏览器返回事件

文章目录 popstate事件&#xff1a;点击浏览器前进&#xff0c;后退会触发popstate事件即&#xff0c;在同一文档的两个历史记录条目之间导航会触发该事件 useEffect(() > {const handlePageBack () > {// 此处写你想要触发的事件console.log(浏览器返回按钮被点击了&a…...

python用selenium网页模拟时无法定位元素解决方法1

进行网页模拟时&#xff0c;有时我们明明可以复制出元素的xpath&#xff0c;但是用selenium的xpath click无法点击到元素。这种情况有几种原因&#xff0c;本文写其中一种——iframe 比如下图网址&#xff0c;第二行出现iframe&#xff0c;则往下的行内元素都会定位不到&#…...

css中文字书写方向

writing-mode 是 CSS 中的一个属性&#xff0c;用于设置文本、内联元素、表格单元格和表格列的书写方向、文本排列以及块流方向。以下是对 writing-mode 属性的详细介绍&#xff1a; 1. 语法和值 语法&#xff1a;writing-mode: horizontal-tb | vertical-rl | vertical-lr |…...

医学王者刊!影响因子自创刊只增不减,3区跃升1区,国人发文占比6成!

【SciencePub学术】今天给大家推荐的是一本医学领域的SCI&#xff0c;是1本颇富潜力的国产期刊。影响因子自创刊以来就逐年上涨&#xff0c;凭借自己的努力从中科院3区跃迁至中科院1区&#xff0c;据说很多人已经靠信息差吃上了这本期刊的红利&#xff0c;接下来给大家解析一下…...

数据建设实践之大数据平台(五)

安装hive 上传安装包到/opt/software目录并解压 [bigdata@node101 software]$ tar -zxvf hive-3.1.3-with-spark-3.3.1.tar.gz -C /opt/services [bigdata@node101 services]$ mv apache-hive-3.1.3-bin apache-hive-3.1.3 配置环境变量 export JAVA_HOME=/opt/services…...

js原型和类---prototype,__proto__,new,class

原型和原型链 在js中&#xff0c;所有的变量都有原型&#xff0c;原型也可以有原型&#xff0c;原型最终都指向Object 什么是原型 在js中&#xff0c;一个变量被创建出来&#xff0c;它就会被绑定一个原型&#xff1b;比如说&#xff0c;任何一个变量都可以使用console.log打…...

bevfomer self-att to transformer to tensorrt

self-attentation https://blog.csdn.net/weixin_42110638/article/details/134016569 query input* Wq key input* Wk value input* Wv output 求和 query . key * value detr multiScaleDeformableAttn Deformable Attention Module&#xff0c;在图像特征上&#…...

LFM2.5-1.2B-Thinking在Ollama上的真实体验:生成速度、内容质量实测

LFM2.5-1.2B-Thinking在Ollama上的真实体验&#xff1a;生成速度、内容质量实测 1. 模型初体验与部署 1.1 第一印象&#xff1a;轻量但强大 当我第一次在Ollama上看到LFM2.5-1.2B-Thinking这个模型时&#xff0c;最吸引我的是它"小身材大能量"的特点。作为一个仅有…...

wechat-need-web:基于Manifest V3的微信网页版访问架构解析与实现方案

wechat-need-web&#xff1a;基于Manifest V3的微信网页版访问架构解析与实现方案 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 微信网页版访问限制…...

数学建模实战:用熵权法+PCA搞定你的综合评价问题(附Python完整代码与数据)

数学建模实战&#xff1a;用熵权法PCA搞定你的综合评价问题&#xff08;附Python完整代码与数据&#xff09; 在数学建模竞赛中&#xff0c;综合评价问题一直是让参赛者头疼的难题。如何从一堆看似杂乱无章的指标中&#xff0c;提炼出关键信息&#xff0c;给出客观公正的评价&a…...

小型葡萄除梗破碎机的设计【三维proe+7张cad图纸+CAXA图纸+毕业论文】

小型葡萄除梗破碎机是葡萄加工领域的关键设备&#xff0c;其核心作用在于高效分离葡萄果粒与果梗&#xff0c;同时实现果粒的适度破碎&#xff0c;为后续发酵或榨汁工艺提供优质原料。传统人工除梗破碎效率低、劳动强度大&#xff0c;且易因操作差异影响原料品质。该设备通过机…...

SmolVLA企业应用:轻量级VLA模型赋能AGV分拣与桌面机械臂

SmolVLA企业应用&#xff1a;轻量级VLA模型赋能AGV分拣与桌面机械臂 1. 引言&#xff1a;当机器人开始“看懂”世界 想象一下&#xff0c;你对着一个机械臂说&#xff1a;“把那个红色的方块拿起来&#xff0c;放到蓝色的盒子里。”然后它真的照做了。这不是科幻电影&#xf…...

如何为Windows 11 LTSC系统一键安装微软商店:3分钟解决应用生态难题

如何为Windows 11 LTSC系统一键安装微软商店&#xff1a;3分钟解决应用生态难题 【免费下载链接】LTSC-Add-MicrosoftStore Add Windows Store to Windows 11 24H2 LTSC 项目地址: https://gitcode.com/gh_mirrors/ltscad/LTSC-Add-MicrosoftStore 你是否在使用Windows …...

实践之漏洞挖掘(弱口令)

前言&#xff1a;经过我的不懈努力&#xff0c;也是挖到了弱口令&#xff0c;嘻嘻&#xff0c;学校的&#xff0c;虽然没有泄露什么隐私&#xff0c;但是我交了要更新就是学校的漏洞&#xff0c;过不过都没关系&#xff0c;没过我下次就找有隐私的后台再交嘻嘻正题&#xff1a;…...

基于 N-gram 全新模型:嵌入扩展新范式,实现轻量化 MoE 高效进化

在技术领域&#xff0c;我们常常被那些闪耀的、可见的成果所吸引。今天&#xff0c;这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力&#xff0c;让我们得以一窥未来的轮廓。然而&#xff0c;作为在企业一线构建、部署和维护复杂系统的实践者&#xff0c;我们深知…...

Aimmy:重新定义游戏公平性,AI技术为视障玩家打造的智能瞄准革命

Aimmy&#xff1a;重新定义游戏公平性&#xff0c;AI技术为视障玩家打造的智能瞄准革命 【免费下载链接】Aimmy Universal Second Eye for Gamers with Impairments (Universal AI Aim Aligner (AI Aimbot) - ONNX/YOLOv8 - C#) 项目地址: https://gitcode.com/gh_mirrors/ai…...

2026年,哪款AI最适合写小说?创作者的终极工具指南

在2026年的今天&#xff0c;AI写作工具已经深度融入小说创作的全流程。对于网文作者、短剧编剧和漫剧创作者而言&#xff0c;选择一款合适的AI工具&#xff0c;不仅能提升创作效率&#xff0c;更能直接影响作品的商业化潜力。然而&#xff0c;面对市面上琳琅满目的AI工具&#…...