前端组件库造轮子——Message组件开发教程
前端组件库造轮子——Message组件开发教程
前言
本系列旨在记录前端组件库开发经验,我们的组件库项目目前已在Github开源,下面是项目的部分组件。文章会详细介绍一些造组件库轮子的技巧并且最后会给出完整的演示demo。

文章旨在总结经验,开源分享,有问题的话也希望路过的大佬指正。
组件开发流程
样式和动画
首先我们来考虑样式,对于message的调用我们下面再讲。
样式的话,无非就是实现一个这样消息弹出框,同时加上弹出时的动画,这里借助vue的transition来实现。

这些都是简单的内容,代码量很少我就直接贴在这里了。
<transition name="message-fade">
<div class="message"><p class="message-content"></p>
</div>
</transition>.message {position: fixed;top: 20px;left: 50%;z-index: 50;box-sizing: border-box;display: flex;align-items: center;padding: 15px 15px 15px 20px;overflow: hidden;background-color: #f0f9eb;border: 1px solid #ebeef5;border-radius: 5px;transition: opacity 0.3s, transform 0.4s, top 0.4s;transform: translateX(-50%);
}
.message-fade-enter-active,
.message-fade-leave-active {opacity: 0;transform: translate(-50%, -100%);
}.message-content {color: #67c23a;font-size: 14px;margin: 0;
}
当然现在这个message是只有空壳一样的内容,我们需要实现的效果是,有一个message函数接口,我们可以调用这个接口后弹出这个消息框。这其实就是和其它一些组件不太一样的地方,他的实现更倾向于一个接口函数一样。
写一个函数当然不是问题,问题是怎么实现调用函数后渲染我们的消息框出来。
这里就需要了解一下vue中渲染DOM的知识点了。
h函数和render函数
在vue中,很多文件的开发都是在.vue文件的,这种文件开发是分为三大块来写,可以像类似写HTML时的感觉,这也是vue的卖点之一,让新手更易于上手。
但是我们要知道,.vue实际上也是需要通过一些打包工具来编译成js代码才能执行。
h函数就是把.vue中的代码编辑成一个虚拟DOM,最终会把template解析为render函数返回虚拟DOM,这点可以在Vue Dev Tools中看到:

也就是说,h函数是负责创建虚拟DOM,render是负责把这个虚拟DOM返回出去
接口函数
通过上面的介绍,大概不难猜出这个接口函数应该如何实现了,其实就是创建一个虚拟DOM出来包裹住我们的message组件,在利用render函数渲染出来即可。
import element from "./message.vue";
import { createVNode, render } from "vue";export default function message(options) {if (typeof options === "string") {options = {message: options as string,};}const params = {...options,};// vue2 的写法// new Vue(render:() => createVNode(element)).mount();const div = document.createElement("div"); // 创建一个divconst vnode = createVNode(element, params); // 创建一个message组件的虚拟DOMrender(vnode, div); // 渲染虚拟DOMdocument.body.appendChild(div.firstElementChild); // 加入到body中
}
那我们既然可以调用message接口函数了,那么在message组件中还有一些逻辑需要实现——在执行结束后关闭掉弹出来的消息框。
这里就是利用v-show控制开关消息框,用定时器回调来解决关闭,我们可以利用props接收存在时间duration,这样我们的基本功能就算完成了,但是message组件还存在很多细节可以补充。
// message.vue
<transition name="message-fade"><div class="message" v-show="visible"><p class="message-content">{{ message }}</p></div>
</transition>const visible = ref(false);
let timer = null;
const start = () => {visible.value = true;if (timer !== null) {clearTimeout(timer);}if (props.duration > 0) {timer = setTimeout(() => {visible.value = false;}, props.duration);}
};onMounted(() => {start();
});onUnmounted(() => {if (timer !== null) {clearTimeout(timer);}
});
回调删除节点的性能优化
在刚刚上面完成的组件中,会发现当我们多次触发了message后,哪怕duration过了,节点也依然存在在body中,这些节点只是被隐藏了,并没有随着持续时间结束后删除掉。

这样显然是不太合理的,并且操作多了会存在一些性能问题,因此我们需要在这个组件在持续时间结束后可以被删除掉。
这里我们可以在动画结束后,派发出一个destroy事件
<transition name="message-fade" @after-leave="$emit('destroy')"> // 派发删除操作<div class="message" v-show="visible"><p class="message-content">{{ message }}</p></div></transition>
这个$emit('destroy')会调用我们传进来的props中的onDestroy函数
// message.tsconst div = document.createElement("div");
const vnode = createVNode(element, params);
+ vnode.props.onDestroy = () => { // 在参数props中挂载销毁函数
+ render(null, div); // 利用render移除div节点
+ };
render(vnode, div);
document.body.appendChild(div.firstElementChild);
连续多次弹出的用户体验优化
当我们连续触发多次message时,会弹出多个消息,对于这多个消息,我们不希望会重叠在一起发生覆盖的情况,我们希望的是可以像下面这样。

那我们如何实现上面的效果呢?
我们可以在props中加一个offset属性,该属性为message组件的离视屏顶部的距离。
然后我们还需要知道上个节点的距离是多少,因此我们需要把连续点出的节点都记录起来,具体来说就是用一个数组把他们存起来,数组中的值按上一节点的offset基础上加合适的距离即可。
// message.ts+ const instances: VNode[] = [];
export default function message(options) {...+ let offset = options.offset || 20;+ instances.forEach((vnode: VNode) => {
+ offset += vnode.el.offsetHeight + 20;
+ });const params = {...options,
+ offset,};const div = document.createElement("div");const vnode = createVNode(element, params);vnode.props.onDestroy = () => {render(null, div); // render会移除dom,注意:此方法在vue2中无法使用
+ instances.pop();};render(vnode, div);document.body.appendChild(div.firstElementChild);
+ instances.push(vnode);
}
同时,我们需要在渲染出message组件中,加上新的offset位置。
// message.vue<transition name="message-fade" @after-leave="$emit('destroy')"><div class="message" v-show="visible" :style="topStyle"> // 更改top位置<p class="message-content">{{ message }}</p></div>
</transition>const topStyle = computed(() => {return {top: `${props.offset}px`,};
});
演示demo
完整项目demo
结语
Message组件的核心开发功能就是上面这些,其他更多的详细功能开发可以参考Hview-ui项目源码
如果想要了解更多的组件轮子开发,或者组件库开发流程,更多详细的组件开发过程更新在GitHub项目源码,最后觉得我们项目or文章不错可以点个star,点点小手支持一下,也欢迎各路大佬为我们的开源项目添砖加瓦。
相关文章:
前端组件库造轮子——Message组件开发教程
前端组件库造轮子——Message组件开发教程 前言 本系列旨在记录前端组件库开发经验,我们的组件库项目目前已在Github开源,下面是项目的部分组件。文章会详细介绍一些造组件库轮子的技巧并且最后会给出完整的演示demo。 文章旨在总结经验,开…...
单片机第二季:温度传感器DS18B20
目录 1,DS18B20介绍 2,DS18B20数据手册 2.1,初始化时序 2.2,读写时序 3,DS18B20工作流程 4,代码 1,DS18B20介绍 DS18B20的基本特征: (1)内置集成ADC,外部数字接…...
抓包工具fiddler的基础知识
目录 简介 1、作用 2、使用场景 3、http报文分析 3.1、请求报文 3.2、响应报文 4、介绍fiddler界面功能 4.1、AutoResponder(自动响应器) 4.2、Composer(设计请求) 4.3、断点 4.4、弱网测试 5、app抓包 简介 fiddler是位于客户端和服务端之间的http代理 1、作用 监控浏…...
监控基本概念
监控:这个词在不同的上下文中有不同的含义,在讲到监控MySQL或者监控Redis时,这里只涉及数据采集和可视化,不涉及告警引擎和事件处理。要是监控系统的话,不但包括数据采集和可视化,而且也包括告警和事件发送…...
【数据结构】 七大排序详解(壹)——直接插入排序、希尔排序、选择排序、堆排序
文章目录 🍀排序的概念及引用🐱👤排序的概念🐱👓排序运用🐱🐉常见的排序算法 🌴插入排序🎋基本思想:🛫直接插入排序📌算法步骤&…...
【Linux】高级IO --- Reactor网络IO设计模式
人其实很难抵制诱惑,人只能远离诱惑,所以千万不要高看自己的定力。 文章目录 一、LT和ET模式1.理解LT和ET的工作原理2.通过代码来观察LT和ET工作模式的不同3.ET模式高效的原因(fd必须是非阻塞的)4.LT和ET模式使用时的读取方式 二…...
Agisoft Metashape相机标定笔记
Lens Calibration(镜头标定) 使用Metashape进行自动相机标定是可能的。Metashape使用LCD显示屏作为标定目标(可选:使用打印的棋盘格图案,但需保证它是平坦的且单元格是正方形)。 相机标定步骤支持全相机标定矩阵的估计ÿ…...
vue-cropper在ie11下选择本地图片后,无显示、拒绝访问的问题
问题:vue-cropper在ie11下选择本地图片后,网页上并未显示出图片,打开F12有报错:拒绝访问blabla的。但是在chrome下一切正常。 开发环境:node14.17.5 , vue2 , vue-cropper0.6.2 , macOS big sur 11.4(M1). 解决办法&…...
Excel VSTO开发11-自定义菜单项
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 11 自定义菜单项 自定义菜单项可以在插件启动时候添加,即增加到ThisAddIn_Startup() 内。 下面以具体代码说明&#x…...
stm32之30.DMA
DMA(硬件加速方法)一般用于帮运比较大的数据(如:摄像头数据图像传输),寄存器-》DMA-》RAM 或者 RAM-》DMA-》寄存器提高CPU的工作效率 源码-- #include "myhead.h" #include "adc.h"#…...
【LeetCode75】第四十九题 数组中的第K个最大元素
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目很简单,就是给我们一个数组,让我们返回第K大的元素。 那么很直观的一个做法就是我们直接对数组进行降序排序…...
嵌入式面试笔试刷题(day14)
文章目录 前言一、进程控制块1.PCB控制块的作用2.PCB的存储位置 二、进程的三级映射三、return , exit, pthread_exit四、pthread_join作用五、互斥锁和信号量的区别六、怎么判断链表是否有环总结 前言 本篇文章继续我们的刷题之路。 一、进程控制块 这里只讲解进程的PCB控制…...
好用免费的Chat GPT(亲测有用)
1、MindLink麦灵 MindLink麦灵 点进登录后 普通用户可以提问100次 2、你问我答 你问我答 无限次数的。 3、灵感 灵感 点击链接后会提示你如何下载使用。 这个有win版和mac版,点击登陆后,每日都会有30次GPT3/3.5的提问。 4、WebTab 在浏览器插件中…...
SpringBoot项目--电脑商城【上传头像】
一、易错点 1.错误写法: 把文件存到数据库中,需要图片时访问数据库,数据库将文件解析为字节流返回,最后写到本地的某一个文件.这种方法太耗费资源和时间了 2.正确写法: 将对应的文件保存在操作系统上,然后再把这个文件路径记录下来,因为在记录路径的…...
优化SOCKS5的方法
在今天的互联网世界中,保护个人隐私和提升网络速度至关重要。作为一种常用的代理协议,SOCKS5代理服务器不仅可以保护您的隐私,还可以实现更快速的网络访问。本文将为您介绍一些优化SOCKS5代理服务器的方法,以提高网络速度和安全性…...
使用 HelpLook Chatbot,让AI聊天机器人变成销售经理
想要增强AI聊天机器人销售技巧的话,我们需要一个强大的搭建工具来帮助我们增加客户互动,通过很多的客户互动数据来支撑和锻炼我们的AI聊天机器人。在本篇文章中,looklook将会系统地来说说该如何定制聊天机器人的行为。 使用AI聊天机器人的好处…...
MT9700 80mΩ,可调快速响应限流配电开关芯片
MT9700 80mΩ,可调快速响应限流配电开关芯片 特征 符合USB规范 集成80mΩ电源MOSFET 低电源电流 15μA典型开启状态 1μA典型关闭状态 宽输入电压Range:2.4V到5.5V 快速瞬态响应:<2μs 反向电流流阻塞 热关机保护 热插件应…...
RabbitMQ之延迟队列
RabbitMQ之延迟队列 1. 延迟队列概念2. 延迟队列使用场景3. RabbitMQ 中的 TTL3.1 消息设置 TTL3.2 队列设置 TTL3.3 两者的区别 4. 整合 SpringBoot4.1 创建项目4.2 添加依赖4.3 修改配置文件4.4 添加 Swagger 配置类 5. 队列 TTL5.1 代码架构图5.2 配置文件类代码5.3 消息生产…...
k8s部署手册-v06
一、基础配置 1.修改主机名 hostnamectl set-hostname k8s-master01 hostnamectl set-hostname k8s-master02 hostnamectl set-hostname k8s-master03 hostnamectl set-hostname k8s-node01 hostnamectl set-hostname k8s-node022.添加 主机名与IP地址解析 cat > /etc/ho…...
Qt 5.15集成Crypto++ 8.7.0(MSVC 2019)笔记
一、背景 笔者已介绍过在Qt 5.15.x中使用MinGW(8.10版本)编译并集成Crypto 8.7.0。 但是该编译出来的库(.a和.dll)不适用MSVC(2019版本)构建环境,需要重新编译(.lib或和.dll…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
