卡片式组件封装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.rhkb.cn/news/381069.html

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

相关文章

从千台到十万台,浪潮信息InManage V7解锁智能运维密码

随着大模型技术的深度渗透&#xff0c;金融行业正经历着前所未有的智能化变革。从“投顾助手”精准导航投资蓝海&#xff0c;到“智能客服”秒速响应客户需求&#xff0c;大模型以其对海量金融数据的深度挖掘与高效利用&#xff0c;正显著提升金融服务的智能化水准&#xff0c;…

Python爬虫(2) --爬取网页页面

文章目录 爬虫URL发送请求UA伪装requests 获取想要的数据打开网页 总结完整代码 爬虫 Python 爬虫是一种自动化工具&#xff0c;用于从互联网上抓取网页数据并提取有用的信息。Python 因其简洁的语法和丰富的库支持&#xff08;如 requests、BeautifulSoup、Scrapy 等&#xf…

Springboot同时支持http和https访问

springboot默认是http的 一、支持https访问 需要生成证书&#xff0c;并配置到项目中。 1、证书 如果公司提供&#xff0c;则直接使用公司提供的证书&#xff1b; 如果公司没有提供&#xff0c;也可自己使用Java自带的命令keytool来生成&#xff1a; &#xff08;1&#x…

postman创建mock server

B站博主的说明&#xff1a;

开源模型应用落地-FastAPI-助力模型交互-进阶篇-RequestDataclasses(三)

一、前言 FastAPI 的高级用法可以为开发人员带来许多好处。它能帮助实现更复杂的路由逻辑和参数处理&#xff0c;使应用程序能够处理各种不同的请求场景&#xff0c;提高应用程序的灵活性和可扩展性。 在数据验证和转换方面&#xff0c;高级用法提供了更精细和准确的控制&#…

【05】LLaMA-Factory微调大模型——初尝微调模型

上文【04】LLaMA-Factory微调大模型——数据准备介绍了如何准备指令监督微调数据&#xff0c;为后续的微调模型提供高质量、格式规范的数据支撑。本文将正式进入模型微调阶段&#xff0c;构建法律垂直应用大模型。 一、硬件依赖 LLaMA-Factory框架对硬件和软件的依赖可见以下…

广州机房搬迁网络部署方案

新机房网络部署应包括核心模块、业务模块、光传输模块、安全模块、流量采集模块、路由模块、带外管理模块等&#xff0c;每个模块都根据业务需求规划成多个POD&#xff08;Point Of Delivery&#xff0c;基本物理设计单元&#xff09;。 核心模块部署主要实现各业务模块的高速互…

【D3.js in Action 3 精译_018】2.4 向选择集添加元素

当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可视化最佳实践&#xff08;下&#xff09;1.4 本章小结 第二章…

Express+mysql单表分页条件查询

声明&#xff08;自己还没测试过&#xff0c;只提供大概逻辑&#xff0c;什么多表连接查询可以在原基础上添加&#xff09; class /*** param connection Express的mysql数据库链接对象* current 当前页* pageSize 一页显示行数* where [{key:id,operator:,value15}], key查询…

js拖拽div的例子

当需要在网页中实现拖拽功能时&#xff0c;可以使用JavaScript来实现。下面是一个简单的例子&#xff0c;演示如何实现拖拽一个 <div> 元素&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <…

动态路由协议 —— EIGRP 与 OSPF 的区别

EIGRP&#xff08;增强内部网关路由协议&#xff09;和 OSPF&#xff08;开放式最短路径优先&#xff09;是两种最常见的动态路由协议&#xff0c;主要是用来指定路由器或交换机之间如何通信。将其应用于不同的情况下&#xff0c;可提高速率、延迟等方面的性能。那么它们之间到…

微信小程序数组绑定使用案例(二)

一、数组事件绑定&#xff0c;事件传递数据 1.wxml <text>姓名&#xff1a;{{name}} </text> <block wx:for"{{list}}"><button bind:tap"nameClick2" data-name"{{item}}">修改:{{item}}</button> </block&…

【Linux知识点汇总】07 Linux系统防火墙相关命令,关闭和开启防火墙、开放端口号

​完整系列文章目录 【Linux知识点汇总】 心血来潮突然想起之前写过的系列文章【Linux知识点汇总】还未完结&#xff0c;那么今天就继续吧 说明&#xff1a;这个系列的内容&#xff0c;在系列【Linux服务器Java环境搭建】中会经常用到&#xff0c;大家可以自行查找相关命令 一、…

springboot开发实用篇

一、Mongodb &#xff08;1&#xff09;简介 MongoDB是一个开源、高性能、无模式的文档型数据库。NoSQL数据库产品中的一种&#xff0c;是最像关系型数据库的非关系型数据库。 数据库&#xff1a;永久性存储&#xff0c;修改频率极低 Mongodb&#xff1a;永久性存储与临时存…

使用百度语音技术实现文字转语音

使用百度语音技术实现文字转语音 SpringBootVue前后端分离项目 调用api接口需要使用AK和SK生成AccessToken,生成getAccessToken的接口有跨域限制,所以统一的由后端处理了 部分参数在控制台->语音技术->在线调试里面能找到 Controller RestController RequestMapping(&q…

游戏常用运行库安装包 Game Runtime Libraries Package

游戏常用运行库安装包&#xff08;Game Runtime Libraries Package&#xff09;是一个整合了多种游戏所需运行库的安装程序&#xff0c;旨在帮助玩家和开发者解决游戏无法正常运行的问题。该安装包支持从Windows XP到Windows 11的系统&#xff0c;并且具备自动检测系统并推荐合…

【python】OpenCV—Extreme Points in the Contour

文章目录 1、需求描述2、功能实现3、更多的例子4、完整代码5、参考 1、需求描述 给一张图片&#xff0c;找出其轮廓&#xff0c;并画出轮廓的上下左右极值点 输入图片 输出效果 2、功能实现 # 导入必要的包 import imutils import cv2 # 加载图像&#xff0c;将其转换为灰度…

【数据集处理工具】将COCO格式数据集的val.json与tett.json文件合并为一个json

合并COCO数据集JSON文件的Python脚本 1、目的2、功能概述3、使用方法4、注意事项5、 代码部分 1、目的 此Python脚本旨在帮助用户合并多个COCO格式的数据集JSON文件&#xff0c;特别适用于将验证集和测试集的标注数据整合到单一文件中。 该脚本假设各个数据集的类别信息&…

django踩坑(四):终端输入脚本可正常执行,而加入crontab中无任何输出

使用crontab执行python脚本时&#xff0c;有时会遇到脚本无法执行的问题。这是因为crontab在执行任务时使用的环境变量与我们在终端中使用的环境变量不同。具体来说&#xff0c;crontab使用的环境变量是非交互式(non-interactive)环境变量&#xff0c;而终端则使用交互式(inter…

国内访问Docker Hub慢问题解决方法

在国内访问Docker Hub时可能会遇到一些困难&#xff0c;但幸运的是&#xff0c;有多种解决方案可以帮助你顺利下载Docker镜像。以下是一些有效的解决方案&#xff1a; 配置Docker镜像源&#xff1a;你可以通过配置Docker的daemon.json文件来使用国内镜像源&#xff0c;比如DaoC…