当前位置: 首页 > ai >正文

React - 封装礼物PK条组件

(一)版本1 

import React from 'react';
import './index.less';interface PKBarProps {matchTitle: string;leftLabel: string;rightLabel: string;leftImageUrl: string;rightImageUrl: string;leftValue: number;rightValue: number;remainingTime: string;skin: number;minPercent?: number; // 新增最小占比
}const PKBar: React.FC<PKBarProps> = ({matchTitle,leftLabel,rightLabel,leftImageUrl,rightImageUrl,leftValue,rightValue,remainingTime,skin,minPercent = 8,
}) => {const totalValue = leftValue + rightValue;const leftPercent = totalValue > 0? Math.max((leftValue / totalValue) * 100, minPercent): 50;const rightPercent = totalValue > 0? Math.max((rightValue / totalValue) * 100, minPercent): 50;const adjustedLeftPercent = leftPercent > 100 - minPercent ? 100 - minPercent : leftPercent;const adjustedRightPercent = rightPercent > 100 - minPercent ? 100 - minPercent : rightPercent;const markers = skin === 0? ['+8流量', '+4流量', '+2流量', '+2流量', '+4流量', '+8流量']: ['5张', '4张', '2张', '4张', '5张'];const intervalWidth = 100 / (markers.length + 1); // 每个区间的宽度// 计算每个区间的中点位置const markerPositions = markers.map((_, index) => `${(index + 1) * intervalWidth}%`);return (<div className={`pk-container skin-${skin}`}><img className="pk-rectangle" src={require('@/component/PKBar/images/Rectangle.png')} alt="Rectangle"/><span className="pk-time">{matchTitle} {remainingTime}</span><div className="pk-header"><div className="pk-left-image"><img src={leftImageUrl} alt="Left"/><span className="pk-label">{leftLabel}</span></div><div className="pk-right-image"><img src={rightImageUrl} alt="Right"/><span className="pk-label">{rightLabel}</span></div></div><div className="pk-bar"><divclassName="pk-left"style={{width: `${adjustedLeftPercent}%`,background: 'linear-gradient(to right, #FF6B6B, #FF8E53, #FFAAA5 98%, #FFFFFF)',}}></div><span className="pk-value pk-left-value">{leftValue}</span><divclassName="pk-right"style={{width: `${adjustedRightPercent}%`,background: 'linear-gradient(to left, #1E66FF, #4568DC, #A770EF 98%, #FFFFFF)',}}></div><span className="pk-value pk-right-value">{rightValue}</span>{/* 刻度线容器 */}<div className="pk-ticks">{markers.map((_, index) => (<divkey={index}className="pk-tick"style={{left: `${(index + 1) * intervalWidth}%`,}}></div>))}</div></div><div className="pk-markers">{markerPositions.map((pos, index) => (<spankey={index}className="pk-marker"style={{left: pos,transform: 'translateX(-50%)',}}>{markers[index]}</span>))}</div></div>);
};
export default PKBar;
.pk-container {width: 707px;height: 183px;background-color: rgba(0, 0, 0, 0.3); /* 设置透明黑色背景 */border-radius: 10px;padding: 10px; /* 确保边距一致 */box-sizing: border-box; /* 确保 padding 不影响宽度 */position: relative; // 确保容器是定位元素的参考
}.pk-rectangle {position: absolute;top: 0;left: 50%;transform: translateX(-50%);width: 280px;height: 39px;
}.pk-header {display: flex;justify-content: space-between;align-items: center;width: 100%;margin: 10px 0 0 0;
}.pk-left-image, .pk-right-image {display: flex;align-items: center;gap: 12px;
}.pk-left-image img, .pk-right-image img {width: 67px;height: 67px;
}.pk-label {font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;font-weight: 600;font-size: 31px;text-align: center;line-height: 51px;color: #fff;
}.pk-time {font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;font-weight: 400; // 字重400font-size: 28px; // 字体大小28pxline-height: 34px; // 行高34pxcolor: #fff; // 白色字体position: absolute; // 绝对定位top: 2px; // 垂直居中相对于 pk-rectangleleft: 50%; // 水平居中transform: translateX(-50%); // 修正水平居中偏移text-align: center;
}.pk-left, .pk-right {//min-width: 8%; // 设置最小宽度,确保颜色可见height: 100%;transition: width 0.3s ease; // 添加平滑过渡效果
}.pk-left-value, .pk-right-value {font-weight: 700;font-size: 28px;font-family: "PingFang SC", "Microsoft YaHei",sans-serif;line-height: 45.05px;color: white;position: absolute;top: 50%;transform: translateY(-50%);
}.pk-left-value {left: 10px;
}.pk-right-value {right: 10px;
}.pk-bar {width: calc(100% - 20px);/* 减去 10px 左右的 padding */height: 40px;border-radius: 10px;position: absolute;display: flex;overflow: hidden;left: 10px;/* 确保位置从左边有 10px 距离 */
}.pk-ticks {position: absolute;top: 0;left: 0;width: 100%;height: 100%;z-index: 1; // 确保刻度线位于条的上层
}.pk-tick {position: absolute;top: 4px; // 距离 PK 条顶部 4pxheight: calc(100% - 8px); // 高度减少 8px,以留下上下 4px 的间距width: 2px; // 刻度线宽度background-color: white; // 刻度线颜色opacity: 0.5; // 半透明效果
}
.pk-markers {position: absolute;top: 125px; /* 根据展示图调整位置 */width: 100%; /* 与 PKBar 的宽度一致 */left: 0; /* 与 PKBar 的左边距一致 */font-size: 20px; /* 确保刻度字体大小合适 */font-weight: 400;line-height: 32px;color: white; /* 刻度文字颜色 */z-index: 2; /* 确定顺序不被覆盖 */
}.pk-marker {position: absolute;text-align: center;transform: translateX(-50%); /* 确保文字居中 */font-size: 24px;font-weight: 400;line-height: 32px;
}/* 针对皮肤的不同布局,可以通过条件类名调整 */
.pk-container.skin-0 .pk-markers {font-size: 12px; /* 按需求调整字体大小 */
}.pk-container.skin-1 .pk-markers {font-size: 14px; /* 道具刻度文字稍大 */
}

(二)版本2

优化后的代码示例:

1. 修正百分比计算逻辑:
const calculatePercents = (leftValue: number, rightValue: number, minPercent: number) => {const total = leftValue + rightValue;if (total === 0) return { left: 50, right: 50 };let leftPercent = (leftValue / total) * 100;let rightPercent = (rightValue / total) * 100;if (leftPercent < minPercent) {leftPercent = minPercent;rightPercent = 100 - minPercent;} else if (rightPercent < minPercent) {rightPercent = minPercent;leftPercent = 100 - minPercent;}return { left: leftPercent, right: rightPercent };
};const { left: adjustedLeftPercent, right: adjustedRightPercent } = calculatePercents(leftValue, rightValue, minPercent);

2.布局优化:

发现版本一即使算出了定位,但是由于是字符串,很难居中定位,为此需要将span的外围包裹一层div,通过div容器去精准定位

    <div className="pk-markers">{markerPositions.map((pos, index) => (<divkey={index}className="pk-marker-container"style={{position: 'absolute',left: pos,transform: 'translateX(-50%)', // 使用动态计算的 transformheight: '100%',display: 'flex',alignItems: 'center',pointerEvents: 'none',textAlign: 'center',}}><span className="pk-marker-text" style={{width: '100%'}}>{markers[index]}</span></div>))}</div>
.pk-markers {position: absolute;top: 125px; /* 根据实际情况调整 */width: calc(100% - 20px); /* 与 pk-bar 一致 */left: 10px; /* 与 pk-bar 一致 */height: 32px;font-size: 20px;font-weight: 400;line-height: 32px;color: white;z-index: 2;pointer-events: none;
}.pk-marker-container {position: absolute;top: 0;height: 100%;display: flex;justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */
}.pk-marker-text {white-space: nowrap; /* 防止换行 */text-align: center;font-weight: 400;font-size: 24px;line-height: 32px;
}

import React from 'react';
import './index.less';interface PKBarProps {matchTitle: string;leftLabel: string;rightLabel: string;leftImageUrl: string;rightImageUrl: string;leftValue: number;rightValue: number;remainingTime: string;skin: number;minPercent?: number; // 新增最小占比
}const PKBar: React.FC<PKBarProps> = ({matchTitle,leftLabel,rightLabel,leftImageUrl,rightImageUrl,leftValue,rightValue,remainingTime,skin,minPercent = 8,
}) => {const calculatePercents = (leftValue: number, rightValue: number, minPercent: number) => {const total = leftValue + rightValue;if (total === 0) return { left: 50, right: 50 };let leftPercent = (leftValue / total) * 100;let rightPercent = (rightValue / total) * 100;if (leftPercent < minPercent) {leftPercent = minPercent;rightPercent = 100 - minPercent;} else if (rightPercent < minPercent) {rightPercent = minPercent;leftPercent = 100 - minPercent;}return { left: leftPercent, right: rightPercent };};const { left: adjustedLeftPercent, right: adjustedRightPercent } = calculatePercents(leftValue, rightValue, minPercent);const markers = skin === 0? ['+8流量', '+4流量', '+2流量', '+2流量', '+4流量', '+8流量']: ['5张', '4张', '2张', '4张'];const intervalWidth = 100 / (markers.length + 1); // 每个区间的宽度// 计算每个区间的中点位置const markerPositions = markers.map((_, index) => `${(index + 1) * intervalWidth}%`);console.log('markerPositions:', markerPositions)return (<div className={`pk-container skin-${skin}`}><img className="pk-rectangle" src={require('@/component/PKBar/images/Rectangle.png')} alt="Rectangle"/><span className="pk-time">{matchTitle} {remainingTime}</span><div className="pk-header"><div className="pk-left-image"><img src={leftImageUrl} alt="Left"/><span className="pk-label">{leftLabel}</span></div><div className="pk-right-image"><img src={rightImageUrl} alt="Right"/><span className="pk-label">{rightLabel}</span></div></div><div className="pk-bar"><divclassName="pk-left"style={{width: `${adjustedLeftPercent}%`,background: 'linear-gradient(to right, #FF6B6B, #FF8E53, #FFAAA5 98%, #FFFFFF)',}}></div><span className="pk-value pk-left-value">{leftValue}</span><divclassName="pk-right"style={{width: `${adjustedRightPercent}%`,background: 'linear-gradient(to left, #1E66FF, #4568DC, #A770EF 98%, #FFFFFF)',}}></div><span className="pk-value pk-right-value">{rightValue}</span>{/* 刻度线容器 */}<div className="pk-ticks">{markers.map((_, index) => (<divkey={index}className="pk-tick"style={{left: `${(index + 1) * intervalWidth}%`,}}></div>))}</div></div><div className="pk-markers">{markerPositions.map((pos, index) => (<divkey={index}className="pk-marker-container"style={{position: 'absolute',left: pos,transform: 'translateX(-50%)', height: '100%',display: 'flex',alignItems: 'center',pointerEvents: 'none',textAlign: 'center',}}><span className="pk-marker-text" style={{width: '100%'}}>{markers[index]}</span></div>))}</div></div>);
};
export default PKBar;
.pk-container {width: 707px;height: 183px;background-color: rgba(0, 0, 0, 0.3); /* 设置透明黑色背景 */border-radius: 10px;padding: 10px; /* 确保边距一致 */box-sizing: border-box; /* 确保 padding 不影响宽度 */position: relative; // 确保容器是定位元素的参考
}.pk-rectangle {position: absolute;top: 0;left: 50%;transform: translateX(-50%);width: 280px;height: 39px;
}.pk-header {display: flex;justify-content: space-between;align-items: center;width: 100%;margin: 10px 0 0 0;
}.pk-left-image, .pk-right-image {display: flex;align-items: center;gap: 12px;
}.pk-left-image img, .pk-right-image img {width: 67px;height: 67px;
}.pk-label {font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;font-weight: 600;font-size: 31px;text-align: center;line-height: 51px;color: #fff;
}.pk-time {font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;font-weight: 400; // 字重400font-size: 28px; // 字体大小28pxline-height: 34px; // 行高34pxcolor: #fff; // 白色字体position: absolute; // 绝对定位top: 2px; // 垂直居中相对于 pk-rectangleleft: 50%; // 水平居中transform: translateX(-50%); // 修正水平居中偏移text-align: center;
}.pk-left, .pk-right {//min-width: 8%; // 设置最小宽度,确保颜色可见height: 100%;transition: width 0.3s ease; // 添加平滑过渡效果
}.pk-left-value, .pk-right-value {font-weight: 700;font-size: 28px;font-family: "PingFang SC", "Microsoft YaHei",sans-serif;line-height: 45.05px;color: white;position: absolute;top: 50%;transform: translateY(-50%);
}.pk-left-value {left: 10px;
}.pk-right-value {right: 10px;
}.pk-bar {width: calc(100% - 20px);/* 减去 10px 左右的 padding */height: 40px;border-radius: 10px;position: absolute;display: flex;overflow: hidden;left: 10px;/* 确保位置从左边有 10px 距离 */
}.pk-ticks {position: absolute;top: 0;left: 0;width: 100%;height: 100%;z-index: 1; // 确保刻度线位于条的上层
}.pk-tick {position: absolute;top: 4px; // 距离 PK 条顶部 4pxheight: calc(100% - 8px); // 高度减少 8px,以留下上下 4px 的间距width: 2px; // 刻度线宽度background-color: white; // 刻度线颜色opacity: 0.5; // 半透明效果
}
.pk-markers {position: absolute;top: 125px; /* 根据实际情况调整 */width: calc(100% - 20px); /* 与 pk-bar 一致 */left: 10px; /* 与 pk-bar 一致 */height: 32px;font-size: 20px;font-weight: 400;line-height: 32px;color: white;z-index: 2;pointer-events: none;
}.pk-marker-container {position: absolute;top: 0;height: 100%;display: flex;justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */
}.pk-marker-text {white-space: nowrap; /* 防止换行 */text-align: center;font-weight: 400;font-size: 24px;line-height: 32px;
}/* 针对皮肤的不同布局,可以通过条件类名调整 */
.pk-container.skin-0 .pk-markers {font-size: 12px; /* 按需求调整字体大小 */
}.pk-container.skin-1 .pk-markers {font-size: 14px; /* 道具刻度文字稍大 */
}

http://www.xdnf.cn/news/9258.html

相关文章:

  • winform LiveCharts2的使用--图表的使用
  • 小土堆pytorch--现有网络模型的使用及修改
  • 数据结构中无向图的邻接矩阵详解
  • 鸿蒙OSUniApp 实现的数据可视化图表组件#三方框架 #Uniapp
  • Rust 学习笔记:迭代器
  • 组合型回溯+剪枝
  • OpenCV CUDA模块图像处理------颜色空间处理之颜色空间转换函数cvtColor()
  • Axure中继器学习笔记
  • DB2数据库HADR配置及详解
  • Femap许可证与网络安全策略
  • arcgis字段计算器中计算矢量面的每个点坐标
  • vscode开发stm32,main.c文件中出现很多报错影响开发解决日志
  • 【脚本】一键部署脚本
  • 深入理解设计模式之命令模式
  • 公共场所人脸识别设备备案合规要点
  • [STM32学习笔记(九)]CubeMX项目使用系统定时器SysTick的中断服务函数进行定时
  • AWS之AI服务
  • 《OpenFeign 最佳实践:三大优雅调用远程服务的方式》​
  • 一种C# 的SM4 的 加解密的实现,一般用于医疗或者支付
  • 如何在WordPress网站中添加相册/画廊
  • 【分治】计算右侧小于当前元素的个数
  • Java集合框架详解:List、Set、Map及其实现类
  • 电子信息科学与技术专业生涯规划书-嵌入式方向(大一下)
  • 《计算机组成原理》第 3 章 - 系统总线
  • 微服务难题?Nacos服务发现来救场
  • 向量数据库对比和选择:Pinecone、Chroma、FAISS、Milvus、Weaviate
  • sqli-第三十二关——bypass addslashes
  • 使用redis代替session的登录校验
  • 企业微信内部网页开发流程笔记
  • [Java恶补day8] 3. 无重复字符的最长子串