React封装组件:步骤条的实现和封装
前言
最近项目里需要用到步骤条的功能,但是ui
给出的设计图我一看在antd
上都没有这种样式的步骤条
啊,所以得自己手动实现封装一个步骤条组件
来使用,这是封装后的步骤条效果图:
实现思路:
首先我是使用了ul
中的每个li
,用浮动:float:left
的方式将每个li
向左浮动,我们将这个步骤条
分成三大部分
,首(第一个li)、中(中间的li)、尾(最后一个li)
,第一个li
我们可以拆解为一个长方形的div右边
加上一个css实现的一个span三角形;最后一个的li
跟第一个正好相反:一个长方形的div左边
加上一个css实现的一个span三角形;中间部分的li
就是结合在一起:一个div前后加上三角形就行了;
代码实现部分:
<ul>
{items?.map((item: StepObjType, index: number) => {
const stepNumber = index + 1;
let node = undefined;
if (stepNumber == 1) {
node = (
<li key={item.key} style={{ width: `calc( 100% / ${items.length})` }}>
<StepContent stepNumber={stepNumber} title={item?.title} />
<span
className={classnames(styles.less, {
[styles.bgBorderColor]: current !== stepNumber,
})}
></span>
</li>
);
} else if (index == items.length - 1) {
node = (
<li key={item.key} style={{ backgroundColor: current == stepNumber ? "#007eff" : "#f5f5f5f5", width: `calc( 100% / ${items.length})` }}>
<StepAfterNode stepNumber={stepNumber} />
<StepContent stepNumber={stepNumber} title={item?.title} />
</li>
);
} else {
node = (
<li key={item.key} style={{ width: `calc( 100% / ${items.length})` }}>
<StepAfterNode stepNumber={stepNumber} />
<StepContent stepNumber={stepNumber} title={item?.title} />
<span
className={classnames(styles.less, styles.right, {
[styles.bgBorderColor]: current !== stepNumber,
})}
></span>
</li>
);
}
return node;
})}
<div className={styles.clearfix}></div>
</ul>
这里可以看到我是分成了三个部分
然后进行了处理,我们还对步骤条进行数据封装,然后步骤条
的数量就动态去items
数组的长度就行了,我这里是分成了4
个步骤:
type StepObjType = {
key: string;
title: string;
content: React.ReactNode | string | undefined;
};
interface CustomStepsProps {
current: number;
items: StepObjType[];
}
import ProCard from "@ant-design/pro-card";
import CustomSteps from "../components/Steps";
import { useState } from "react";
import { Button, Space } from "antd";
const TestUiComponent: React.FC = () => {
const [current, setCurrent] = useState(1);
const stepsList = [
{
key: "first",
title: "1、步骤1",
content: "first",
},
{
key: "seconde",
title: "2、步骤2",
content: "seconde",
},
{
key: "3",
title: "3、步骤3",
content: "3333",
},
{
key: "4",
title: "4、步骤4",
content: "44",
},
];
return (
<ProCard>
<CustomSteps current={current} items={stepsList} />
<Space style={{marginTop:20}}>
<Button
type="primary"
onClick={() => {
setCurrent((pre) => pre - 1);
}}
>
后退
</Button>
<Button
type="primary"
onClick={() => {
setCurrent((pre) => pre + 1);
}}
>
前进
</Button>
</Space>
</ProCard>
);
};
export default TestUiComponent;
我们也可以看一下三个步骤条效果:
完整效果预览
完整代码
这里就两个文件不到200行的代码:css文件
和tsx文件
CustomSteps文件:
import classnames from "classnames";
import styles from "./index.less";
type StepObjType = {
key: string;
title: string;
content: React.ReactNode | string | undefined;
};
interface CustomStepsProps {
current: number;
items: StepObjType[];
}
const CustomSteps: React.FC<CustomStepsProps> = ({ current = 1, items = [] }) => {
// 步骤条内容
const StepContent = ({ title, stepNumber }: { title: string; stepNumber: number }) => (
<div
className={classnames(styles.block, {
[styles.bgColor]: current !== stepNumber,
[styles.active]: current == stepNumber,
})}
>
{title}
</div>
);
// 这里只有最后步骤条或者中间的步骤条才有,第一个没有
const StepAfterNode = ({ stepNumber }: { stepNumber: number }) => (
<samp
className={classnames(styles.less1, styles.left, {
[styles.bgColor]: current !== stepNumber,
})}
></samp>
);
return (
<div className={styles.stepsPage}>
<ul>
{items?.map((item: StepObjType, index: number) => {
const stepNumber = index + 1;
let node = undefined;
if (stepNumber == 1) {
node = (
<li key={item.key} style={{ width: `calc( 100% / ${items.length})` }}>
<StepContent stepNumber={stepNumber} title={item?.title} />
<span
className={classnames(styles.less, {
[styles.bgBorderColor]: current !== stepNumber,
})}
></span>
</li>
);
} else if (index == items.length - 1) {
node = (
<li key={item.key} style={{ backgroundColor: current == stepNumber ? "#007eff" : "#f5f5f5f5", width: `calc( 100% / ${items.length})` }}>
<StepAfterNode stepNumber={stepNumber} />
<StepContent stepNumber={stepNumber} title={item?.title} />
</li>
);
} else {
node = (
<li key={item.key} style={{ width: `calc( 100% / ${items.length})` }}>
<StepAfterNode stepNumber={stepNumber} />
<StepContent stepNumber={stepNumber} title={item?.title} />
<span
className={classnames(styles.less, styles.right, {
[styles.bgBorderColor]: current !== stepNumber,
})}
></span>
</li>
);
}
return node;
})}
<div className={styles.clearfix}></div>
</ul>
{/* content */}
<div className={styles.stepscontent}>{items[current - 1]?.content}</div>
</div>
);
};
export default CustomSteps;
css文件:
.stepsPage {
.clearfix {
clear: both;
}
ul {
width: 100%;
padding: 0;
list-style: none;
}
li {
position: relative;
float: left;
// width: 376px;
// width: calc(100% / 4);
height: 40px;
margin-bottom: 10px;
list-style: none;
flex: 1;
}
.less {
top: 0;
border-color: transparent transparent transparent #007eff;
border-style: dashed dashed dashed solid;
border-width: 25px 0 15px 20px;
transition: all 0.5;
} /*dashed 设置透明*/
.less1 {
top: 0;
border-color: transparent transparent transparent #fff;
border-style: dashed dashed dashed solid;
border-width: 25px 0 15px 20px;
}
.right {
right: 0;
}
.left {
left: 0;
}
samp {
position: absolute;
z-index: 2;
display: block;
}
span {
position: relative;
z-index: 3;
display: block;
float: left;
}
.block {
z-index: 1;
float: left;
// width: 357px;
width: 92%;
height: 40px;
color: #222222;
line-height: 40px;
text-align: center;
vertical-align: middle;
background: #007eff;
}
.bgColor {
background: #f5f5f5;
}
.bgBorderColor {
border-color: transparent transparent transparent #f5f5f5;
}
.active {
color: #fff;
}
.stepscontent {
width: 100%;
height: 200px;
margin-top: 20px;
background-color: #f7f7f7;
}
@media screen and (max-width: 1230px) {
.block {
width: 90%;
}
}
@media screen and (max-width: 848px) {
.block {
width: 86%;
}
}
}
最后
这里封装的一个步骤条
组件就实现啦,如果上面的实现有啥问题,欢迎各位大佬指点指点啊~~ , 感谢大家!
转载自:https://juejin.cn/post/7366549142107570195