不使用第三方库怎么实现【前端引导页】功能?

news/2024/5/14 12:04:51/文章来源:https://blog.csdn.net/web220507/article/details/127251926

前言

随着应用功能越来越多,繁多而详细的功能使用和说明文档,已经不能满足时代追求 快速 的需求,而 引导页(或分步引导) 本质就是 化繁为简,将核心功能以更简单、简短、明了的文字指引用户去使用对应的功能,特别是 ToB 的项目,各种新功能需求迭代非常快,免不了需要 引导页 的功能来快速帮助用户引导。

下面我们通过两个方面来围绕着【前端引导页】进行展开:

  • 哪些第三方库可以直接使用快速实现功能?
  • 如何自己实现前端引导页的功能?

第三方库的选择

如果你不知道如何做技术选型,可以看看 山月大佬 的这一篇文章 在前端中,如何更好地做技术选型?,下面就简单列举几个相关的库进行简单介绍,具体需求具体分析选择,其他和 API 使用、具体实现效果可以通过官方文档或对应的 README.md 进行查看。

vue-tour

vue-tour 是一个轻量级、简单且可自定义的 Tour 插件,配置也算比较简单清晰,但只适用于 Vue2 的项目,具体效果可以直接参考对应的前面链接对应的内容。

driver.js

driver.js 是一个强大而轻量级的普通 JavaScript 引擎,可在整个页面上驱动用户的注意力,只有 4kb 左右的体积,并且没有外部依赖,不仅高度可定制,还可以支持所有主流浏览器。

shepherd.js

shepherd.js 包含的 API 众多,大多场景都可以通过其对应的配置得到,缺点就是整体的包体积较大,并且配置也比较复杂,配置复杂的内容一般都需要进行二次封装,将可变和不可变的配置项进行抽离,具体效果可见其 官方文档

intro.js

intro.js 是是一个开源的 vanilla Javascript/CSS 库,用于添加分步介绍或提示,大小在 10kB左右,属于轻量级的且无外部依赖,详情可见 官方文档

实现引导页功能

引导页核心功能其实就两点:

  • 一是 高亮部分
  • 二是 引导部分

而这两点其实真的不难实现,无非就是 引导部分 跟着 高亮部分 移动,并且添加一些简单的动画或过渡效果即可,也分为 蒙层引导无蒙层引导,这里介绍相对比较复杂的 蒙层引导,下面就简单介绍两种简单的实现方案。

cloneNode + position + transition

核心实现:

  • 高亮部分 通过 el.cloneNode(true) 复制对应目标元素节点,并将克隆节点添加到蒙层上* 通过 margin(或 tranlateposition 等)实现克隆节点的位置与目标节点重合
  • 引导部分 通过 position: fixed 实现定位效果,并通过动态修改 left、top 属性实现引导弹窗跟随目标移动
  • 过渡动画 通过 transition 实现位置的平滑移动
  • 页面 位置/内容 发生变化时(如:resize、scroll 事件),需要重新计算位置信息

缺点:

  • 目标节点需要被深度复制
  • 不能实现边引导边操作

效果演示:

核心代码:

// 核心配置参数
const selectors = [{selector: "#btn1",message: "点此【新增】数据!",},{selector: "#btn2",message: "小心【删除】数据!",},{selector: "#btn3",message: "可通过此按钮【修改】数据!",},{selector: "#btn4",message: "一键【完成】所有操作!",},
];// Guide.vue
<script setup> import { computed, onMounted, ref } from "vue";const props = defineProps({selectors: Array,
});const guideModalRef = ref(null);
const guideBoxRef = ref(null);const index = ref(0);
const show = ref(true);
let cloneNode = null;
let currNode = null;let message = computed(() => {return props.selectors[index.value]?.message;
});const genGuide = (hasChange = true) => {// 前置操作cloneNode && guideModalRef.value?.removeChild(cloneNode);// 所有指引完毕if (index.value > props.selectors.length - 1) {show.value = false;return;}// 获取目标节点信息currNode =currNode || document.querySelector(props.selectors[index.value].selector);const { x, y, width, height } = currNode.getBoundingClientRect();// 克隆节点cloneNode = hasChange ? currNode.cloneNode(true) : cloneNode;cloneNode.id = currNode.id + "_clone";cloneNode.style = `margin-left: ${x}px;margin-top: ${y}px;`;// 指引相关if (guideBoxRef.value) {const halfClientHeight = guideBoxRef.value.clientHeight / 2;guideBoxRef.value.style = ` left:${x + width + 10}px; top:${y <= halfClientHeight ? y : y - halfClientHeight + height / 2}px;`;guideModalRef.value?.appendChild(cloneNode);}
};// 页面内容发生变化时,重新计算位置
window.addEventListener("resize", () => genGuide(false));
window.addEventListener("scroll", () => genGuide(false));// 上一步/下一步
const changeStep = (isPre) => {isPre ? index.value-- : index.value++;currNode = null;genGuide();
};onMounted(() => {genGuide();
}); </script><template><teleport to="body"><div v-if="show" ref="guideModalRef" class="guide-modal"><div ref="guideBoxRef" class="guide-box"><div>{{ message }}</div><button class="btn" :disabled="index === 0" @click="changeStep(true)">上一步</button><button class="btn" @click="changeStep(false)">下一步</button></div></div></teleport>
</template><style scoped> .guide-modal {position: fixed;z-index: 999;left: 0;right: 0;top: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.3);
}
.guide-box {width: 150px;min-height: 10px;border-radius: 5px;background-color: #fff;position: absolute;transition: 0.5s;padding: 10px;text-align: center;
}
.btn {margin: 20px 5px 5px 5px;
} </style> 

z-index + position + transition

核心实现:

  • 高亮部分 通过控制 z-index 的值,让目标元素展示在蒙层之上
  • 引导部分 通过 position: fixed 实现定位效果,并通过动态修改 left、top 属性实现引导弹窗跟随目标移动
  • 过渡动画 通过 transition 实现位置的平滑移动
  • 页面 位置/内容 发生变化时(如:resize、scroll 事件),需要重新计算位置信息

缺点:

  • 当目标元素的父元素 position: fixed | absolute | sticky 时,目标元素的 z-index 无法超过蒙版层(可参考 shepherd.jssvg 解决方案)

效果演示:

核心代码:

<script setup>
import { computed, onMounted, ref } from "vue";const props = defineProps({selectors: Array,
});const guideModalRef = ref(null);
const guideBoxRef = ref(null);const index = ref(0);
const show = ref(true);
let preNode = null;let message = computed(() => {return props.selectors[index.value]?.message;
});const genGuide = (hasChange = true) => {// 所有指引完毕if (index.value > props.selectors.length - 1) {show.value = false;return;}// 修改上一个节点的 z-indexif (preNode) preNode.style = `z-index: 0;`;// 获取目标节点信息const target =preNode = document.querySelector(props.selectors[index.value].selector);target.style = `position: relative; z-index: 1000;`;const { x, y, width, height } = target.getBoundingClientRect();// 指引相关if (guideBoxRef.value) {const halfClientHeight = guideBoxRef.value.clientHeight / 2;guideBoxRef.value.style = ` left:${x + width + 10}px; top:${y <= halfClientHeight ? y : y - halfClientHeight + height / 2}px;`;}
};// 页面内容发生变化时,重新计算位置
window.addEventListener("resize", () => genGuide(false));
window.addEventListener("scroll", () => genGuide(false));const changeStep = (isPre) => {isPre ? index.value-- : index.value++;genGuide();
};onMounted(() => {genGuide();
});
</script><template><teleport to="body"><div v-if="show" ref="guideModalRef" class="guide-modal"><div ref="guideBoxRef" class="guide-box"><div>{{ message }}</div><button class="btn" :disabled="index === 0" @click="changeStep(true)">上一步</button><button class="btn" @click="changeStep(false)">下一步</button></div></div></teleport>
</template><style scoped> .guide-modal {position: fixed;z-index: 999;left: 0;right: 0;top: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.3);
}
.guide-box {width: 150px;min-height: 10px;border-radius: 5px;background-color: #fff;position: absolute;transition: 0.5s;padding: 10px;text-align: center;
}
.btn {margin: 20px 5px 5px 5px;
} </style> 

【扩展】SVG 如何完美解决 z-index 失效的问题?

这里以 shepherd.js 来举例说明,先来看起官方文档展示的 demo 效果:

在上述展示的效果中进行了一些验证:

  • 正常点击 NEXT 进入下一步指引,仔细观察 SVG 相关数据发生了变化
  • 等到指引部分指向代码块的内容区时,复制了此时 SVG 中和 path 相关的参数
  • 返回到第一步很明显此时的高亮部分高度较小,将上一步复制的参数直接替换当前 SVG 中和 path 相关的参数,此时发现整体 SVG 高亮内容宽高发生了变化

核心结论:通过 SVG 可编码的特点,利用 SVG 来实现蒙版效果,并且在绘制蒙版时,预留出目标元素的高亮区间(即 SVG 不需要绘制这一部分),这样就解决了使用 z-index 可能会失效的问题。

最后

以上就是一些简单实现,但还有很多细节需要考虑,比如:边引导边操作的实现、定位原因导致的图层展示问题等仍需要优化。

相信大部分人第一直觉是:直接使用第三方库实现功能就好了呀,自己实现功能不全、也未必好用,属实没有必要。

对于这一点其实在早前看到的一句话说的挺好:了解底层实现原理比使用库本身更有意义,当然每个人的想法不同,不过如果你想开始了解原理又不能立马挑战一些高深的内容,为什么不先从自己感兴趣的又不是那么复杂的功能开始呢?

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

Oracle数据库 | SQL语句解析

个人主页&#xff1a;&#x1f497;wei_shuo的个人主页 &#x1f3c0; Hello World &#xff01;&#x1f3c0; 文章目录一.Oracle启动及登录1.1 服务手启动即关闭1.2 SQL* PLUS命令二. 表的创建和维护2.1 创建表2.2 修改表2.3 重命名表2.4 截断表2.5 删除表三. 数据完整性与约…

【C++学习】类与对象(中)

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《C学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 类与对象&#xff08;中&#xff09;&#x1f638;构造函数&#x1f639;概念&#x1f639;特性&…

常见数据结构-散列表(上)理论

一&#xff0c;散列表理解 散列表的英文叫“Hash Table”&#xff0c;我们平时也叫它“哈希表”或者“Hash 表”&#xff0c;散列表用的是数组支持按照下标随机访问数据的特性&#xff0c;所以散列表其实就是数组的一种扩展&#xff0c;基于数组演化而来。 散列表是通过散列函…

bp神经网络performance怎么看,BP神经网络用什么软件

1、除了MATLAB能做BP神经网络&#xff0c;还有其他什么软件能做 除了MATLAB能做BP神经网络&#xff0c;还有其他什么软件能做 理论上编程语言都可以&#xff0c;比如VB&#xff0c;C语言&#xff0c;过程也都是建模、量化、运算及结果输出&#xff08;图、表&#xff09;&…

JavaScript设计模式(一):面向对象编程 - 继承

JavaScript设计模式 - 面向对象编程灵活的语言-JavaScript用对象收编变量对象的另一种形式(函数对象)真假对象(闭包和类)一个检测类函数的祖先写的都是看到的-面向对象编程创建一个类&#xff08;三种方式&#xff09;类的属性和方法通过闭包来实现类的静态变量定义&#xff0c…

二十一、JAVA调用存储过程(Oracle专栏)

2022年9月28日16:33:11目录 &#x1f3c6;一、存储过程的创建及调用 ⭐️1.1、PLSQL编程 ⭐️1.2、程序结构 ⭐️1.3、变量 1.3.1、普通变量 1.3.2、引用型变量 1.3.3、记录型变量 ⭐️1.4、流程控制 1.4.1、条件分支 1.4.2、循环 &#x1f3c6;二、游标 ⭐️2.1、…

网状神经系统的典型特点,网状结构神经系统

脑干网状结构对肌紧张既有抑制作用也有加强作用。 选择A对。理由如下&#xff1a;网状结构中存在有抑制和加强肌紧张和肌运动区域&#xff0c;分别成为抑制区和易化区。抑制区位于网状结构的腹内侧部分。易化区位于网状结构的背外侧、脑桥被盖、中脑中央灰质及被盖。 &#x…

什么是RFID技

什么是RFID技术 RFID射频识别是一种非接触式的自动识别技术&#xff0c;它通过射频信号自动识别目标对象并获取相关数据&#xff0c;识别无需人工干预&#xff0c;可工作于各种恶劣环境。RFID技术可识别高速运动物体并同时识别多个标签&#xff0c;操作快捷方便。 ​​​​​…

Bootstrap——flex布局(定义弹性盒子、排列方向、内容排列、项目对齐、自身对齐、自动对等、等宽变换、自动边距、包裹、排序、对齐内容)

Bootstrap4与Bootstrap3最大的区别是Bootstrap 4使用弹性盒子来布局&#xff0c;而不是使用浮动来布局。弹性盒子也是CSS的一种新的布局模式&#xff0c;更适合响应式的设计。 布局的传统解决方案,基于盒状模型&#xff0c;依赖display属性 position属性 float属性。它对…

dif分页、排序、过滤功能

分页功能 接口中只有查询全部数据接口有时候数据量非常大&#xff0c;所以需要用到分页功能&#xff0c;在rest_framework中提供了三种分页的方法 一.PageNumberPagination 第一步&#xff1a;定义一个分页类继承PageNumberPagination from rest_framework.pagination import P…

Day02 -尚品汇-路由传递参数

围绕这个开展 1》在Header.vue里面 2》在Header.vue里面 第一种方式&#xff1a;&#xff08;字符串形式写法&#xff09; 传递params参数 3》在index.js里面 【此处用的是params参数 需要占位】 4》在Header.vue里面 【params写法】 1--4的效果图 我还想加一个传…

NTFS文件系统详解(二)MBR\EBR基本信息

NTFS文件系统详解&#xff08;二&#xff09;MBR\EBR基本信息一、MBR结构分析1. 第一个分区表项2. 第二个分区表项3. 第三个分区表项4. 第四个分区表项二、EBR结构分析1. 第一个分区表项2. 第二个分区表项2.1 第一个分区表项2.2 第二个分区表项2.3 第三个分区表项系列文章目录经…

springBoot实验填报系统

摘要 国内教育行业的快速发展&#xff0c;人们为了能够更加方便地管理学生实验填报&#xff0c;实验填报系统被人们开发出来从而更好地方便管理学生实验填报&#xff0c;一个完美的实验填报系统已经成为各个学校的追求目标。 本系统利用SpringBoot技术进行开发实验填报系统是未…

asp.net旅游网站系统VS开发sqlserver数据库web结构c#编程计算机网页项目

一、源码特点 ASP.NET 旅游网站系统是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为vs2010&#xff0c;数据库为sqlserver2008&#xff0c;使用c#语言开发 asp.net旅游网站系统VS开发sqlserver数…

git基本使用方式整理

文章目录A:配置个人信息B:创建目录C:初始化仓库D:往仓库添加和提交文件E:状态查看命令F:版本回退G:对git占存区的理解H&#xff1a;管理修改I&#xff1a;撤销修改J&#xff1a;删除文件K:关联远程仓库L:仓库克隆在Git安装完成之后&#xff0c;需要配置Git连接的用户信息&#…

python与Electron联合编程记录之八(Hello Flask!)

Hello Flask&#xff01; 既然知道了Electron和Flask信息交换的原理&#xff0c;我们就可以开始进行Electron和Flask的联合编程了。   让我们紧接第三部分“Hello&#xff0c;Electron!”项目继续探索Flask的用法。 1、配置虚拟环境 由于Flask是python编写的&#xff0c;所以…

Python百日进阶-WEB开发】Day156 - 前端基础 之 BootStrap(一)

文章目录一、BootStrap的安装和使用1.1 BootStrap介绍1.2 BootStrap特点1.3 下载使用1.3.1 下载BootStrap:1.3.2 下载 jquery.js1.4 创建项目1.5 bootstrap和vue对比1.5.1 Bootstrap和vue不是一个层级的东西&#xff0c;Vue是框架&#xff0c;bootstrap是基于jQuery的组建库。1…

洛谷 T281315 掌控

PS&#xff1a;如果读过题了可以跳过题目描述直接到题解部分 提交链接&#xff1a;洛谷 T281315 掌控 题目 题目描述 公元 2044 年&#xff0c;人类进入了宇宙纪元。L 国有 nnn 个星球&#xff0c;分别编号为 111 到 nnn &#xff0c;每一星球上有一个球长。有些球长十分强大…

Ryu的安装+使用

ryu的安装 安装RYU&#xff0c;需要安装一些python的套件&#xff1a; python-eventlet python-routes python-webob python-paramiko 安装RYU主要有两种方式&#xff1a; 1、pip安装 pip install ryu git clone https://github.com/osrg/ryu.git cd ryu sudo pip install -…

【路径规划】基于matlab卡尔曼滤波、三次插值极速赛道赛车路径规划【含Matlab源码 2158期】

一、卡尔曼滤波路径追踪优化简介 割草机器人通过比对当前t时刻位置、导航方程之间偏移角度θ和偏移距离d,确定t1时刻的运动方向属于递推型路径追踪。割草机器人工作过程中受到地面起伏等环境因素影响,在采用上述追踪方法时会和预测值产生偏差,造成机器人偏离导航方程,称之为系…