卡片式组件封装demo

效果视频:

卡片组件

样式还得细调~,时间有限,主要记录一下逻辑。

html结构:
在这里插入图片描述

目录

  • 父组件
    • 数据处理
      • 数据格式
    • 父组件的全部代码
  • 子组件
    • 数据处理
      • props参数
    • 样式部分
      • 三个圆点
        • 点击三圆点在对应位置显示查看弹框
        • 点击非内容部分隐藏查看弹框
      • 遮罩层
    • 子组件的全部代码

父组件

数据处理

在父页面进行v-for循环,灵活根据状态可赋值数组,再根据数组的长度调用卡片组件。

数据格式

  • ASTATE:状态;整型,0表示进行中,1表示超期
  • DESCRIPTION:描述;字符串类型;
  • STARTTIME:开始时间;字符串类型,格式为年月日T时分秒
  • PLANENDTIME:结束时间;字符串类型,格式为年月日T时分秒

以上字段在子组件中皆有用到

[{"ASTATE": 0,"DESCRIPTION": "大名称大名称\n名称:21名称21名称21\n名称:21名称21名称21\n时间:2024-7-17","STARTTIME": "2024-01-03T01:02:03","PLANENDTIME": "2024-01-04T01:02:03","ID": 2},{"ASTATE": 2,"DESCRIPTION": "大名称大名称\n名称:21名称21名称21\n名称:21名称21名称21\n时间:2024-7-17","STARTTIME": "2024-01-07T01:02:03","PLANENDTIME": "2024-01-08T01:02:03","ID": 4}
]

父组件的全部代码

<!-- 页面名称 -->
<template><div class="homebox-class"><div class="mainbox"><h2>任务管理</h2><!-- 超期 --><h4 v-if="taskOverdueData.length>0" class="overduetitle">超期 {{taskOverdueData.length}}</h4><div class="outtabsbox"><tab-task-com-vue :width="18" :height="16" v-for="(task,index) in taskOverdueData" :taskData="task" :key="'overdue' + index"></tab-task-com-vue></div><!-- 进行中 --><h4 v-if="taskOngoingData.length>0" class="ongoingtitle">进行中 {{taskOngoingData.length}}</h4><div class="outtabsbox"><tab-task-com-vue :width="18" :height="16" v-for="(task,index) in taskOngoingData" :taskData="task" :key="'ongoing' + index"></tab-task-com-vue></div></div></div>
</template><script>
import testdata from './test.json';
import tabTaskComVue from '@/views/hzevt/abnormal/tabTaskCom.vue';
export default {components: { tabTaskComVue },props: {},data() {return {taskOverdueData: [],taskOngoingData: [],};},watch: {},computed: {},created() { },mounted() {console.log('testdata', testdata);for (var i of testdata) {if (i.ASTATE == 0) {this.taskOngoingData.push(i);} else if (i.ASTATE == 2) {this.taskOverdueData.push(i);}}},methods: {},
};
</script>
<style scoped>
.homebox-class {width: 100%;height: 100%;
}
.mainbox {width: 100%;height: 100%;overflow-y: auto;
}
.mainbox h2 {letter-spacing: 2px;font-size: 1.2vw;
}
.mainbox h4 {margin: 2% 0;font-size: 1vw;
}
.overduetitle {color: #f26950;
}
.ongoingtitle {color: #2cc09c;
}.outtabsbox {display: flex;justify-content: flex-start;flex-wrap: wrap;font-weight: bold;
}
</style>

子组件

数据处理

props参数

宽高单位为百分比。

 props: {width: {//卡片的宽度type: Number,required: true},height: {//卡片的高度type: Number,required: true},taskData: {//父组件传过来对应的item对象type: Object,required: true},},

样式部分

三个圆点

圆点的实现是采用三个div并添加border-radius: 50%的样式。
dots: [1, 2, 3],表示有三个圆点。

<div class="dotbox" @click="showTooltip($event)"><div class="dot" v-for="(dot, index) in dots" :key="index"></div><div v-if="showPopup" @click="toCheckBtn" class="popup" :style="{ top: popupTop + 'px', left: popupLeft + 'px' }">查看</div>
</div>
点击三圆点在对应位置显示查看弹框
  1. 获取目标元素的位置信息:
    getBoundingClientRect() 是一个 DOM API 方法,返回一个 DOMRect 对象,提供了目标元素的大小和其相对于视口的位置信息。

  2. 计算鼠标相对于目标元素的偏移量:
    event.clientXevent.clientY 分别是鼠标指针相对于整个文档的坐标位置。
    dotboxRect.leftdotboxRect.top 分别是目标元素的左上角相对于视口的坐标位置。

  3. 设置popup弹框元素的位置信息:

  4. 显示popup弹框元素:

showTooltip(event) {const dotboxRect = event.currentTarget.getBoundingClientRect();const offsetX = event.clientX - dotboxRect.left;const offsetY = event.clientY - dotboxRect.top;//设置popup弹框元素的位置信息this.popupTop = offsetY + 'px';this.popupLeft = offsetX + 'px';this.showPopup = true;//显示popup弹框元素
},
点击非内容部分隐藏查看弹框

内容部分:

<div class="contentbox" ref="contentRef"></div>
  1. mounted添加监听事件
    ①. 获取点击目标信息:
    ②. 判断点击位置
handleClickOutside(event) {const clickedInsideContentbox = this.$refs.contentRef.contains(event.target);//获取点击目标信息if (!clickedInsideContentbox) {//判断点击位置this.showPopup = false;}
},

遮罩层

根据showPopup动态控制遮罩层的显示和隐藏

<div v-if="showPopup" class="popup-overlay" @click="togglePopup()"></div>

子组件的全部代码

<!-- 首页使用到的tab框组件 -->
<template><div :style="{ width: `${width}%`, height: `${height}%` }" class="tabsbox"><!-- 遮罩层 --><div v-if="showPopup" class="popup-overlay" @click="togglePopup()"></div><div class="tabstitle overduetitle" v-if="taskData.ASTATE==2">超期</div><div class="tabstitle ongoingtitle" v-if="taskData.ASTATE==0">进行中</div><div class="contentbox" ref="contentRef"><div class="contenttitlebox"><div class="content-title" :class="taskData.ASTATE === 0?'state-0':'state-2'">生产异常流程</div><div class="dotbox" @click="showTooltip($event)"><div class="dot" v-for="(dot, index) in dots" :key="index"></div><div v-if="showPopup" @click="toCheckBtn" class="popup" :style="{ top: popupTop + 'px', left: popupLeft + 'px' }">查看</div></div></div><pre class="content-descbox">{{taskData.DESCRIPTION}}</pre><div class="tabsbottombox"><div class="timebox"><img src="@/views/system/index/components/d2-page-cover/image/time1.png" alt=""><div v-if="taskData.STARTTIME.includes('T')">{{taskData.STARTTIME.replace("T", " ").slice(0, 16)}}</div><div v-else>{{taskData.STARTTIME}}</div></div><div class="timebox" style="justify-content: flex-end;"><img src="@/views/system/index/components/d2-page-cover/image/time2.png" alt=""><div v-if="taskData.PLANENDTIME.includes('T')">{{taskData.PLANENDTIME.replace("T", " ").slice(0, 16)}}</div><div v-else>{{taskData.PLANENDTIME.replace("T", " ").slice(0, 16)}}</div></div></div></div></div>
</template><script>
export default {components: {},props: {width: {type: Number,required: true},height: {type: Number,required: true},taskData: {type: Object,required: true},},data() {return {dots: [1, 2, 3],showPopup: false,popupTop: 0,popupLeft: 0,};},watch: {},computed: {},created() { },beforeDestroy() {// 在组件销毁前,移除全局点击事件监听器document.removeEventListener('click', this.handleClickOutside);},mounted() {document.addEventListener('click', this.handleClickOutside);},methods: {showTooltip(event) {const dotboxRect = event.currentTarget.getBoundingClientRect();const offsetX = event.clientX - dotboxRect.left;const offsetY = event.clientY - dotboxRect.top;this.popupTop = offsetY + 'px';this.popupLeft = offsetX + 'px';this.showPopup = true;},togglePopup() {// 点击tabsbox时切换popup状态this.showPopup = false;},// 全局点击事件处理函数,用于关闭弹窗handleClickOutside(event) {const clickedInsideContentbox = this.$refs.contentRef.contains(event.target);if (!clickedInsideContentbox) {this.showPopup = false;}},closePopup() {this.showPopup = false;},// 查看详情toCheckBtn() {//你的操作逻辑},},watch: {},
};
</script>
<style scoped>
.tabsbox {opacity: 0.6;border-radius: 15px;background: rgba(255, 255, 255, 1);border: 1px solid rgba(138, 127, 127, 0.3);box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25);margin: 0 3% 3% 1%;padding: 1%;position: relative;
}
.overduetitle {color: #f26950;
}
.ongoingtitle {color: #2cc09c;
}
.tabstitle {font-size: 0.8vw;height: 15%;border-bottom: 1px solid #e6e8ed;
}
.contentbox {height: 85%;
}
.content-title {font-size: 1vw;height: 10%;padding: 2%;font-weight: bold;position: relative; /* 让元素变为相对定位,以便使用 top 属性 */
}
.content-title::before {content: ""; /* 伪元素用于创建边框 */position: absolute; /* 绝对定位在元素内部 */top: 15px; /* 距离顶部偏移量,根据需要调整 */left: -2px; /* 边框从左侧开始 */height: 100%; /* 高度为元素高度减去偏移量 */
}
/* ASTATE 为 0 时的伪类元素样式 */
.content-title.state-0::before {border-left: 3px solid #2cc09c;
}/* ASTATE 为 2 时的伪类元素样式 */
.content-title.state-2::before {border-left: 3px solid #f26950;
}
.content-descbox {height: 66%;margin: 0 3% 3%;color: #4f545a;font-family: none;font-size: 0.7vw;display: flex;align-items: center;
}
.tabsbottombox {height: 14%;display: flex;
}
.timebox {height: 100%;width: 100%;display: flex;align-items: center;
}
.timebox img {width: 18px;height: 18px;
}
.timebox div {font-size: 0.7vw;margin-left: 4px;
}.contenttitlebox {display: flex;flex-direction: row;flex-wrap: nowrap;justify-content: space-between;
}
.dotbox {display: flex;flex-direction: column;align-items: center;justify-content: center;position: relative;
}
.dotbox:hover {cursor: pointer;
}
.dot {width: 0.2vw;height: 0.3vh;background-color: #787b83;border-radius: 50%;margin: 1.5px;cursor: pointer;
}
.popup {position: absolute;background-color: #fff;padding: 5px 0;z-index: 1000;width: 55px;right: 10px;top: 10px;text-align: center;border-radius: 0.3rem;color: #8e8f95;font-size: 0.8vw;border: 1px solid #ededed;box-sizing: border-box;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.popup:hover {background: #409eff;color: #fff;box-shadow: 0 2px 12px 0 rgb(0 0 0 / 40%);
}
.popup-overlay {position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.5); /* 遮罩层颜色 */z-index: 1; /* 确保遮罩层在popup之下 */border-radius: 15px;
}.tabsbox {/* 默认背景样式 */background-color: #fff;
}
</style>

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

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

相关文章

PHP连接MySQL数据库

PHP本身不具备操作MySQL数据库的能力&#xff0c;需要借助MySQL扩展来实现。 1、PHP加载MySQL扩展&#xff1a;php.ini文件中。&#xff08;不要用记事本打开&#xff09; 2、PHP中所有扩展都是在ext的文件夹中&#xff0c;需要指定扩展所在路径&#xff1a;extension_dir。 3、…

Mysql的语句执行很慢,如何分析排查?

1、检查服务器性能是否存在瓶颈 如果系统资源使用率比较高&#xff0c;比如CPU,硬盘&#xff0c;那访问肯定会慢&#xff0c;如果你发现是Mysl占比比较高&#xff0c;说明Mysql的读写频率高&#xff0c;如果本身网站访问量不大&#xff0c;说明你的sql参数&#xff0c;sql语句查…

【STC89C51单片机】串口通信

【STC89C51单片机】串口通信 串口简介1. 串口接线方式2. 通信过程 相关寄存器1. SBUF&#xff08;Serial Buffer Register&#xff09;2. SCON&#xff08;Serial Control Register&#xff09;3. PCON&#xff08;Power Control Register&#xff09;4. TCON&#xff08;Timer…

记录些Redis题集(4)

Redis 通讯协议(RESP) Redis 通讯协议&#xff08;Redis Serialization Protocol&#xff0c;RESP&#xff09;是 Redis 服务端与客户端之间进行通信的协议。它是一种二进制安全的文本协议&#xff0c;设计简洁且易于实现。RESP 主要用于支持客户端和服务器之间的请求响应交互…

第 8 章 虚拟文件系统(2)

目录 8.3 VFS结构 8.3.1 结构概观 8.3.2 inode 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;查看后续文章。 8.3 VFS结构 8.3.1 结构概观 VFS组成部分&#xff1a; 1. 文件。 2. 文件系统。 1. 文件的表示 inode&#xff1a;包含文件信息及数据存储位置。 上…

001、Mac系统上Stable Diffusion WebUI环境搭建

一、目标 如标题所述&#xff0c;在苹果电脑&#xff08;Mac&#xff09;上搭建一套Stable Diffusion本地服务&#xff0c;以实现本地AI生图目的。 二、安装步骤 1、准备源码【等价于准备软件】 # 安装一系列工具库&#xff0c;包括cmake,protobuf,rust,python3.10,git,wge…

Nginx、LNMP万字详解

目录 Nginx 特点 Nginx安装 添加Nginx服务 Nginx配置文件 全局配置 HTTP配置 状态统计页面 Nginx访问控制 授权用户 授权IP 虚拟主机 基于域名 测试 基于IP 测试 基于端口 测试 LNAMP 解析方式 LNMP转发php-fpm解析 Nginx代理LAMP解析 LNMP部署示例 实…

linux之mysql安装和使用

数据库之Mysql 一、数据库介绍 1、什么是数据库 数据库就是一个存放计算机数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来对数据进行组织和存储的,可以通过数据库提供的多种方法来管理其中的数据。 2、数据库的种类 最常用的…

微分段Microsegmentation简介

目录 微分段Microsegmentation简介什么是微分段&#xff1f;微分段的防范措施微分段的防护层级 基于网络的微分段微分段基本工作机制微分段的角色VxLAN的额外字段 业务链分组与传输策略场景1&#xff1a;三层报文本地转发场景场景2&#xff1a;三层报文跨设备转发场景 微分段的…

中国贸易外经统计年鉴(2006-2023年)

数据年限&#xff1a;2006-2023年全 数据格式&#xff1a;pdf、excel、caj 数据内容&#xff1a;《中国贸易外经统计年鉴》是一部反映中国国内贸易、对外经济贸易和旅游业发展情况的资料性年刊。收录了 中国国内消费品市场、批发和零售业、住宿和餐饮业、国际收支、对外贸易、利…

具有I2S输出的多模数字麦克风ICS-43434咪头LR引脚接地或电源WS接LRCLK

外观和丝印 ICS-43434麦克风3.50 mm x 2.65 mm&#xff0c;丝印为434&#xff08;图片不好拍&#xff0c;隐约可见434&#xff09; 一般描述 ICS-43434 是一款数字 IS 输出底部收音孔麦克风。完整的 ICS-43434 解决方案包括 MEMS 传感器、信号调理、模数转换器、抽取和抗混叠滤…

在mybatis-plus中关于@insert注解自定义批处理sql导致其雪花算法失效而无法自动生成id的解决方法

受到这位作者的启发 > 原文在点这里 为了自己实现批量插入&#xff0c;我在mapper层使用insert注解写了一段自定义sql //自定义的批量插入方法 Insert("<script>" "insert into rpt_material_hour(id,sample_time,rounding_time,cur_month,machine_no…

Elasticsearch 批量更新

Elasticsearch 批量更新 准备条件查询数据批量更新 准备条件 以下查询操作都基于索引crm_flow_info来操作&#xff0c;索引已经建过了&#xff0c;本文主要讲Elasticsearch批量更新指定字段语句&#xff0c;下面开始写更新语句执行更新啦&#xff01; 查询数据 查询指定shif…

视频号矩阵系统,AI自动生成文案,实现批量上传视频和定时发布

在数字化浪潮席卷全球的今天&#xff0c;视频内容已成为信息传播的重要载体。然而&#xff0c;对于众多自媒体创作者和企业而言&#xff0c;如何高效、精准地发布视频内容&#xff0c;依然是一个不小的挑战。幸运的是&#xff0c;随着技术的不断进步&#xff0c;视频号矩阵系统…

Kafka消息队列python开发环境搭建

目录 引言 Kafka 的核心概念和组件 Kafka 的主要特性 使用场景 申请云服务器 安装docker及docker-compose VSCODE配置 开发环境搭建 搭建Kafka的python编程环境 Kafka的python编程示例 引言 Apache Kafka 是一个分布式流处理平台&#xff0c;由 LinkedIn 开发并在 2…

SpringBoot整合阿里云RocketMQ对接,商业版

1.需要阿里云开通商业版RocketMQ 普通消息新建普通主题,普通组,延迟消息新建延迟消息主题,延迟消息组 2.结构目录 3.引入依赖 <!--阿里云RocketMq整合--><dependency><groupId>com.aliyun.openservices</groupId><artifactId>ons-client</…

Qt类 | QLabel类详解

文章目录 一、QLabel类介绍二、Properties&#xff08;属性&#xff09;三、Public Functions&#xff08;公共函数&#xff09;1.构造函数2.alignment与setAlignment函数 -- 标签内容的对齐方式3.buddy与setBuddy函数 -- QLabel关联的伙伴控件4.hasScaledContents与setScaledC…

基于YOLOv8深度学习的水果智能检测系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战、目标检测、卷积神经网络

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

C#字符串基本操作

1、代码 //1、创建字符串&#xff08;获取长度&#xff09;string str "Hello, World!";Console.WriteLine($"string:{str},length:{str.Length}");//2、字符串连接string str1 "Hello, ";string str2 "World!";Console.WriteLine…

在 Windows 11/10/8 上恢复误删除文件的最佳方法

如果您刚刚在计算机上重新安装了 Windows 操作系统&#xff0c;结果硬盘上的所有文件都消失了&#xff0c;有没有办法从 Windows 11/10 中恢复误删除的文件&#xff1f; 许多因素都可能导致 PC 上的文件被删除。除了重新安装操作系统外&#xff0c;其他常见原因还包括意外删除…