【VUE3.0】动手做一套像素风的前端UI组件库---Message

目录

  • 引言
  • 自己整一个UI设计稿
  • 代码编写
    • 1. 设计信息窗口基础样式
    • 2. 设置打开和关闭的方法
    • 3. 编写实例化组件的js文件
    • 4. 看下最终效果
    • 5. 组件完整代码
    • 6. 组件调用方式
  • 总结

引言

本教程基于前端UI样式库 NES.css 的UI设计,自行研究复现。欢迎大家交流优化实现方法~

此次组件库开发基于vue3框架,框架基础搭建过程以及基础素材准备参考:【VUE3.0】动手做一套像素风的前端UI组件库—先导篇

本篇完成的组件为Message,日常项目中较为常见的组件,主要涉及到的内容有:

  • 这次没得 借鉴了,NES.css没有提供这个组件的样式模板。
  • 参考按钮的高光和阴影设计一个具有特色的信息弹窗。
  • 利用vue的transition组件给弹窗一些动画效果。
  • 采用单例模式将信息弹窗放置在全局避免重复。
  • 参考组件库Element Plus的设计使用方式,采用js的方式调用组件并传参。

自己整一个UI设计稿

结合以前玩的一款掌机游戏的提示框

  • 我希望这里的message提示框可以像横幅一样打在公屏上,样式要夸张一些。
  • 提示框在消失的时候可以有一个渐变放大透明的效果,视觉上比较有张力。

大概长这样:
在这里插入图片描述
功能上我需要:

  • 支持传入字符串或对象去调用信息弹窗。
  • 支持successerrorwarninginfo四个子方法去调用信息弹窗。

代码编写

1. 设计信息窗口基础样式

  • 利用box-shadow的内部阴影,结合hsl颜色模型增加背景色20%的亮度来凸显高光部分的样式。
  • 利用vue的transition组件给弹窗设置渐变放大透明度为0的过度效果。
  • 利用hsl颜色模型和vue的css变量,根据传入type类型转换组件颜色的色相、饱和度、亮度,为弹窗的背景绑定参数。

编写vue文件,设置基础的组件布局、颜色以及过度效果:

<template><transition name="scale"><div v-show="state.showMessage" class="pMessage">{{ state.content }}</div></transition>
</template>
<script setup>
import { reactive, ref } from "vue";
const state = reactive({content: "这是一个 message",duration: 1500,type: "primary",showMessage: false,
});
let hue = ref("");
let saturation = ref("");
let light = ref("");
const handleColor = (type) => {switch (type) {case "primary":hue.value = "204";saturation.value = "86%";light.value = "53%";break;case "success":hue.value = "85";saturation.value = "58%";light.value = "53%";break;case "error":hue.value = "10";saturation.value = "75%";light.value = "62%";break;case "warning":hue.value = "51";saturation.value = "93%";light.value = "54%";break;case "info":hue.value = "0";saturation.value = "0%";light.value = "83%";break;}
};
</script>
<style scoped>
.pMessage {--base_hue: v-bind(hue);--base_saturation: v-bind(saturation);--base_light: v-bind(light);color: #f3f3f3;font-size: 40px;font-weight: bold;width: 100%;height: 150px;display: flex;justify-content: center;align-items: center;position: fixed;top: 35%;z-index: 999;background: hsl(var(--base_hue), var(--base_saturation), var(--base_light));box-shadow: inset 0px -30px hsl(var(--base_hue), var(--base_saturation), calc(var(--base_light) + 20%));
}
.scale-enter-active,
.scale-leave-active {transition: 0.2s ease-out;
}
.scale-enter,
.scale-leave-to {transform: scale(2);opacity: 0;
}
</style>

2. 设置打开和关闭的方法

  • 因为是通过js方法去调用组件渲染,那么肯定要对外暴露一个open方法。
  • 为了代码的健壮性,也需要提供一个关闭方法。
  • 信息弹窗打开后需要通过定时器是延时关闭,需要操作好定时器,做一个简易的防抖,保证多次触发弹窗时,只在最后一次触发的延时时间后关闭弹窗。
  • 最后记得将写好的方法以及组件内部的state对象暴露出去,这样在外部js代码中实例化这个组件后,才可以读取到这个方法。

补充第一步vue文件的js内容:

let messageTimer = null;
const open = () => {if (messageTimer) {clearTimeout(messageTimer);messageTimer = null;}handleColor(state.type);state.showMessage = true;messageTimer = setTimeout(() => {state.showMessage = false;}, state.duration);
};
const close = () => {if (messageTimer) {clearTimeout(messageTimer);messageTimer = null;}state.showMessage = false;
};
// 导出这state、open、close,保证外部js可以读取到组件内部方法,这很重要!
defineExpose({ state, open, close });

3. 编写实例化组件的js文件

在vue文件的同级目录下创建对应的js文件。

  • 这里需要使用vue的createApp方法创建一个组件,并挂接在一个新建的dom上,然后将dom挂载在body中。
  • 为了避免多次触发信息弹窗,导致产生dom过多造成卡顿。我们采用单例模式去更新唯一的那个组件实例,而不是一直创建新的组件。
  • 通过initInstance 方法初始化组件。
  • 对外导出pMessage方法,用于更新信息弹窗实例的内容及状态。
  • 在pMessage方法中校验传入的信息:
    • 纯字符串就按默认的参数去渲染。
    • 对象则按照传入的信息结合默认参数去渲染。
    • 最后通过open方法去打开信息弹窗,展示dom。

以下是js内容:

import { createApp } from "vue";
import Message from "./index.vue";let instance;const initInstance = () => {const messageInstance = createApp(Message);// 需要一个容器const container = document.createElement("div");// 再进行挂载 - 挂载之后返回实例上下文instance = messageInstance.mount(container);document.body.appendChild(container);
};function pMessage(option) {if (!instance) initInstance();if (!option) {option = {};}option = typeof option === "string" ? { content: option } : option;instance.state.content = option.content || "这是一个 message";instance.state.duration = option.duration || 1500;instance.state.type = option.type || "primary";instance.open();
}export default pMessage;

补充successerrorwarninginfo四个子方法去调用信息弹窗

在js文件中继续补充代码

// 抽象公共逻辑
const createMessageType = (type) => {return function (content, duration) {return pMessage({content,duration,type,});};
};// 自动生成不同类型的消息方法
["success", "error", "warning", "info"].forEach((type) => {pMessage[type] = createMessageType(type);
});

补充信息弹窗组件的关闭方法

在js文件中继续补充代码

pMessage.close = function () {if (instance && instance.close) {instance.close();}
};

4. 看下最终效果

在这里插入图片描述

5. 组件完整代码

index.vue

<template><transition name="scale"><div v-show="state.showMessage" class="pMessage">{{ state.content }}</div></transition>
</template><script setup>
import { reactive, ref } from "vue";const state = reactive({content: "这是一个 message",duration: 1500,type: "primary",showMessage: false,
});
let messageTimer = null;
const open = () => {if (messageTimer) {clearTimeout(messageTimer);messageTimer = null;}handleColor(state.type);state.showMessage = true;messageTimer = setTimeout(() => {state.showMessage = false;}, state.duration);
};
const close = () => {if (messageTimer) {clearTimeout(messageTimer);messageTimer = null;}state.showMessage = false;
};
let hue = ref("");
let saturation = ref("");
let light = ref("");
const handleColor = (type) => {switch (type) {case "primary":hue.value = "204";saturation.value = "86%";light.value = "53%";break;case "success":hue.value = "85";saturation.value = "58%";light.value = "53%";break;case "error":hue.value = "10";saturation.value = "75%";light.value = "62%";break;case "warning":hue.value = "51";saturation.value = "93%";light.value = "54%";break;case "info":hue.value = "0";saturation.value = "0%";light.value = "83%";break;}
};
defineExpose({ state, open, close });
</script><style scoped>
.pMessage {--base_hue: v-bind(hue);--base_saturation: v-bind(saturation);--base_light: v-bind(light);color: #f3f3f3;font-size: 40px;font-weight: bold;width: 100%;height: 150px;display: flex;justify-content: center;align-items: center;position: fixed;top: 35%;z-index: 999;background: hsl(var(--base_hue), var(--base_saturation), var(--base_light));box-shadow: inset 0px -30px hsl(var(--base_hue), var(--base_saturation), calc(var(--base_light) + 20%));
}.scale-enter-active,
.scale-leave-active {transition: 0.2s ease-out;
}.scale-enter,
.scale-leave-to {transform: scale(2);opacity: 0;
}
</style>

index.js

import { createApp } from "vue";
import Message from "./index.vue";let instance;const initInstance = () => {const messageInstance = createApp(Message);// 需要一个容器const container = document.createElement("div");// 再进行挂载 - 挂载之后返回实例上下文instance = messageInstance.mount(container);document.body.appendChild(container);
};function pMessage(option) {if (!instance) initInstance();if (!option) {option = {};}option = typeof option === "string" ? { content: option } : option;instance.state.content = option.content || "这是一个 message";instance.state.duration = option.duration || 1500;instance.state.type = option.type || "primary";instance.open();
}// 抽象公共逻辑
const createMessageType = (type) => {return function (content, duration) {return pMessage({content,duration,type,});};
};// 自动生成不同类型的消息方法
["success", "error", "warning", "info"].forEach((type) => {pMessage[type] = createMessageType(type);
});pMessage.close = function () {if (instance && instance.close) {instance.close();}
};export default pMessage;

6. 组件调用方式

<template><div class="message"><p-button type="success" @click="openMessageSuccess"> 成功提示 </p-button><p-button type="error" @click="openMessageError"> 失败提示 </p-button><p-button @click="openMessage1"> 普通提示不传参 </p-button><p-button @click="openMessage2"> 普通提示传参 </p-button></div>
</template>
<script setup>
import pMessage from "@/components/message/index.js";
const openMessageSuccess = () => {pMessage.success("成功!");
};
const openMessageError = () => {pMessage.error("失败!");
};
const openMessage1 = () => {pMessage("普通提示不传参");
};
const openMessage2 = () => {pMessage({content: "普通提示传参",duration: 300,type: "primary",});
};
</script>

总结

至此一个完整的像素风信息弹窗组件Message就开发完成了。
本篇主要强化理解了几个点:

  • vue的transition组件的使用方法。
  • js的简易防抖实现逻辑。
  • js设计模式中的单例模式应用。
  • js调用组件封装逻辑。

再接再厉~

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

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

相关文章

《线性代数》学渣笔记

文章目录 1 行列式1.1 克拉默法则1.2 基本性质1.3 余子式 M i j M_{ij} Mij​1.4 代数余子式 A i j ( − 1 ) i j ⋅ M i j A_{ij} (-1)^{ij} \cdot M_{ij} Aij​(−1)ij⋅Mij​1.5 具体型行列式计算&#xff08;化为基本型&#xff09;1.5.1 主对角线行列式&#xff1a;主…

基于数据挖掘的航空客户满意度分析预测系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 航空公司致力于提供多样化的服务以满足乘客需求&#xff0c;包括但不限于提供免费无线网络、免费食物饮品、提供网上预约服务、飞机出口位置、座椅舒适度、卫生状况等&#xff0c;并希望以此提升乘…

SQL面试常见题目

SQL面试常见题目涉及多个方面&#xff0c;包括数据查询、数据操作、表的设计与优化等。以下列举一些经典的SQL面试题目&#xff0c;并附上解析答案&#xff1a; 1. 查询一张表中重复的数据 题目&#xff1a; 给定一个表 employees&#xff0c;包含 id, name, salary 列。如何…

SpringBoot框架之KOB项目 - 配置Mysql与注册登录模块(中)

修改Spring Security 登录验证模式 传统的验证登录模式 公开页面&#xff1a;输入url就可以直接访问授权页面&#xff1a;登录之后才可以访问 Jwt验证模式 容易实现跨域不需要在服务器端存储 对比于传统模式将所有的sessionId换成jwt token access token refresh token 过…

分发饼干00

题目链接 分发饼干 题目描述 注意点 1 < g[i], s[j] < 2^31 - 1目标是满足尽可能多的孩子&#xff0c;并输出这个最大数值 解答思路 可以先将饼干和孩子的胃口都按升序进行排序&#xff0c;随后根据双指针 贪心&#xff0c;将当前满足孩子胃口的最小饼干分配给该孩…

Android开发高频面试题之——Android篇

Android开发高频面试题之——Android篇 Android开发高频面试题之——Java基础篇 Android开发高频面试题之——Kotlin基础篇 Android开发高频面试题之——Android基础篇 1. Activity启动模式 standard 标准模式,每次都是新建Activity实例。singleTop 栈顶复用。如果要启动的A…

关于预处理的一系列问题

1. 预定义符号 C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 2. #define定义常量 #define name stuff 如果定义的 stuff过⻓&#xff0c;可以分成⼏⾏写&#xff0c;除了最后⼀⾏外&#xff0c;每⾏的后⾯都加⼀个反…

win10下使用docker、k8s部署java应用

在上一篇文章 Windows10上Docker和Kubernetes的安装 中&#xff0c;已经介绍了在 Windows10上安装Docker和Kubernetes &#xff0c;有了这个环境基础之后&#xff0c;就可以用来部署服务了 在项目目录下新建Dockfile文件&#xff0c;内容如下&#xff08;请根据实际情况调整&am…

前端——阿里图标的使用

阿里图标 将小图标定义成字体&#xff0c;通过引入字体的方式来展示这些图标 1.打开阿里图标库 https://www.iconfont.cn/ 2.登录 / 注册一个账号 3.选中你需要使用的图标 并且把它加入购物车 4.全部选择完之后 点击右上角 购物车 然后下载代码 5.解压后你下载的文…

Web+Mysql——MyBatis

MyBatis 目标 能够完成Mybatis代理方式查询数据能够理解Mybatis核心配置文件的配置 1&#xff0c;Mybatis 1.1 Mybatis概述 1.1.1 Mybatis概念 MyBatis 是一款优秀的持久层框架&#xff0c;用于简化 JDBC 开发 MyBatis 本是 Apache 的一个开源项目iBatis, 2010年这个项目由…

面试面经|大模型算法岗常见面试题100道

本文提供了一份全面的大模型算法岗位面试题清单&#xff0c;包括基础理论、模型结构、训练微调策略、应用框架、分布式训练和模型推理等方面的知识点&#xff0c;旨在帮助求职者准备相关技术面试。 一、基础篇 1、目前主流的开源模型体系有哪些&#xff1f; Transformer体系&a…

neo4j(spring) 使用示例

文章目录 前言一、neo4j是什么二、开始编码1. yml 配置2. crud 测试3. node relation 与java中对象的关系4. 编码测试 总结 前言 图数据库先驱者 neo4j&#xff1a;neo4j官网地址 可以选择桌面版安装等多种方式,我这里采用的是docker安装 直接执行docker安装命令: docker run…

zabbix“专家坐诊”第256期问答

原作者&#xff1a;乐维社区 原文链接&#xff1a;https://forum.lwops.cn/questions 问题一 Q&#xff1a;zabbix 6.4.18版本的&#xff0c;使用zabbix_agentd2监控mysql数据库&#xff0c;只能在界面配置mysql的相关信息吗&#xff1f;这个在zabbix表里面是明文存储的&#x…

力扣反转链表系列【25. K 个一组翻转链表】——由易到难,一次刷通!!!

力扣《反转链表》系列文章目录 刷题次序&#xff0c;由易到难&#xff0c;一次刷通&#xff01;&#xff01;&#xff01; 题目题解206. 反转链表反转链表的全部 题解192. 反转链表 II反转链表的指定段 题解224. 两两交换链表中的节点两个一组反转链表 题解325. K 个一组翻转…

在python爬虫中xpath方式提取lxml.etree._ElementUnicodeResult转化为字符串str类型

简单提取网页中的数据时发现的 当通过xpath方式提取出需要的数据的text文本后想要转为字符串&#xff0c;但出现lxml.etree._ElementUnicodeResult的数据类型不能序列化&#xff0c;在网上查找到很多说是编码问题Unicode编码然后解码什么的&#xff1b;有些是(导入的xml库而不…

Java : 图书管理系统

图书管理系统的作用&#xff1a; 高效的图书管理 图书管理系统通过自动化管理&#xff0c;实现了图书的采编、编目、流通管理等操作的自动化处理&#xff0c;大大提高了图书管理的效率和准确性。 工作人员可以通过系统快速查找图书信息&#xff0c;实时掌握图书的借还情况&…

【Java】Java中接口与内部类详解

目录 引言 一、接口&#xff08;Interface&#xff09; 1.1 接口的定义 1.1.1 接口的特点 1.2 接口的实现 1.3 接口的继承 1.4 接口的注意事项 1.5 代码示例 二、内部类&#xff08;Inner Class&#xff09; 2.1 内部类特点 2.2 成员内部类 2.2.1 对象的创建 2.…

红外热成像应用场景!

1. 电力行业 设备故障检测&#xff1a;红外热成像仪能够检测电气设备&#xff08;如变压器、电线接头&#xff09;的过热现象&#xff0c;及时发现并定位故障点&#xff0c;预防火灾等安全事故的发生。 水电站查漏&#xff1a;在水电站中&#xff0c;红外热成像仪可用于快速查…

【LLM学习之路】9月22日 第九天 自然语言处理

【LLM学习之路】9月22日 第九天 直接看Transformer 第一章 自然语言处理 自然语言处理发展史 只要看的足够多&#xff0c;未必需要理解语言 统计语言模型发展史 统计语言模型&#xff1a; 判断一个句子是否合理&#xff0c;就计算这个句子会出现的概率 缺点是句子越长越…

掌握Python办公自动化,轻松成为职场高效达人

大家好&#xff0c;今天我们来聊聊为什么要学习和了解Python办公自动化&#xff1f; "自动化应用于高效运营将提高效率" ——比尔盖茨 在日常的工作中&#xff0c;存在很多重复性、规律性的工作。虽然现在有很多办公软件能够在一些方面提高工作效率&#xff0c;但无法…