由于阿里lowcode和alifd/next深度集成,alifd/next的组件样式不满足于现有需求,Ant Design的样式符合现有需求但是需要引入Ant Design,所以想想决定手搓一个。
1、先看效果
2、上代码
components
ProgressSteps.tsx
import React, {createElement} from "react";
import { Balloon } from '@alifd/next';
import "./index.scss";
export interface ProgressStepsProps {
steps?: number;
percent?: number;
size?: [number, number];
direction?: 'horizontal' | 'vertical';
strokeColor?: string;
trailColor?: string;
borderRadius?: number;
width?: string;
height?: string;
stepWidth?: number,
stepHeight?: number,
labelText?: string,
labelColor?: string,
labelSize?: number,
labelBlod?: boolean,
percentageColor?: string,
percentageSize?: number,
percentageBlod?: boolean,
isBalloon?: boolean,
style?: React.CSSProperties;
}
const ProgressSteps: React.FC<ProgressStepsProps> = (props) => {
const {
width,
height,
steps = 10,
percent = 50,
direction = 'horizontal',
strokeColor = '#1890ff',
trailColor = '#f0f0f0',
borderRadius = 2,
stepWidth = 30,
stepHeight = 50,
labelText,
labelColor,
labelSize,
labelBlod,
percentageColor,
percentageSize,
percentageBlod,
isBalloon,
style
} = props;
const filledSteps = (percent / 100) * steps;
const isHorizontal = direction === 'horizontal';
const boxStyle = {
display: 'flex',
alignItems: 'center',
flexDirection: isHorizontal ? 'row' : 'column',
gap: 2,
width,
height,
}
const labelStyle = {
margin: '0 6px',
color: labelColor,
fontSize: labelSize,
fontWeight: labelBlod ? 'bold' : 'normal',
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
}
const stepStyle = {
height: stepHeight,
width: stepWidth,
borderRadius,
transition: 'background 0.3s',
}
const percentageStyle = {
margin: '0 6px',
color: percentageColor,
fontSize: percentageSize,
fontWeight: percentageBlod ? 'bold' : 'normal',
}
return (
<div style={{...boxStyle, ...style}}>
<div style={labelStyle} title={labelText}>
{labelText}
</div>
{Array.from({ length: steps }).map((_, idx) => {
let background = trailColor;
if (idx + 1 <= filledSteps) {
background = strokeColor;
} else if (idx < filledSteps) {
const fillPercent = (filledSteps - idx) * 100;
background = isHorizontal
? `linear-gradient(to right, ${strokeColor} ${fillPercent}%, ${trailColor} 0%)`
: `linear-gradient(to bottom, ${strokeColor} ${fillPercent}%, ${trailColor} 0%)`;
}
return isBalloon ?
(<Balloon
v2
trigger={
<div
key={idx}
style={{
...stepStyle,
background,
}}
/>
}
closable={false}
align="t"
triggerType="hover"
>
<div style={{
fontSize: percentageSize,
fontWeight: percentageBlod ? 'bold' : 'normal',
}}>{percent}%</div>
</Balloon>)
:
(<div
key={idx}
style={{
...stepStyle,
background,
}}
/>)
})}
<div style={percentageStyle}>
{percent}%
</div>
</div>
);
};
export default ProgressSteps;
样式scss
.progress-steps-container {
position: relative;
width: 100%;
margin: 20px 0;
}
.progress-steps-background {
position: absolute;
top: 50%;
left: 0;
width: 100%;
transform: translateY(-50%);
background-color: #f0f0f0;
border-radius: 4px;
}
.progress-steps-foreground {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
background-color: #1890ff;
border-radius: 4px;
transition: width 0.3s;
}
.progress-step {
position: absolute;
top: 50%;
transform: translateY(-50%);
border-radius: 50%;
text-align: center;
color: #fff;
z-index: 1;
}
.progress-step.completed {
background-color: #1890ff;
}
.progress-step.current {
background-color: #1890ff;
}
.progress-step.pending {
background-color: #f0f0f0;
color: #999;
}
.progress-step.partial {
background-color: #f0f0f0;
color: #999;
overflow: hidden;
position: relative;
}
.progress-step-partial-fill {
position: absolute;
top: 0;
left: 0;
bottom: 0;
background-color: #1890ff;
z-index: -1;
}
.next-balloon-normal{
z-index: 9999 !important;
}
lowcode
meta:
import {IPublicTypeComponentMetadata, IPublicTypeSnippet} from '@alilc/lowcode-types';
const ProgressStepsMeta: IPublicTypeComponentMetadata = {
componentName: 'ProgressSteps',
title: 'ProgressSteps',
group: 'xx组件',
category: 'xx类',
docUrl: '',
screenshot: '',
devMode: 'proCode',
npm: {
package: "xxxxxxx",
version: '0.0.1',
exportName: 'ProgressSteps',
main: 'src/index.tsx',
destructuring: true,
subName: '',
},
configure: {
props: [
{
name: 'legend',
type: 'group',
display: 'accordion',
title: {
label: '容器',
},
items: [
{
title: {
label: {
type: 'i18n',
'en-US': 'width',
'zh-CN': '宽度',
},
},
name: 'width',
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
{
componentName: 'NumberSetter',
isRequired: false,
initialValue: 0,
},
],
},
isRequired: true,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'height',
'zh-CN': '高度',
},
},
name: 'height',
setter: {
componentName: 'MixedSetter',
props: {
setters: [
{
componentName: 'StringSetter',
isRequired: false,
initialValue: '',
},
{
componentName: 'NumberSetter',
isRequired: false,
initialValue: 0,
},
],
},
isRequired: true,
},
},
]
},
{
name: 'legend',
type: 'group',
display: 'accordion',
title: {
label: '步骤',
},
items: [
{
title: {
label: {
type: 'i18n',
'en-US': 'steps',
'zh-CN': '条数',
},
},
name: 'steps',
setter: {
componentName: 'NumberSetter',
isRequired: true,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'stepWidth',
'zh-CN': '宽度',
},
},
name: 'stepWidth',
setter: {
componentName: 'NumberSetter',
isRequired: true,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'stepHeight',
'zh-CN': '高度',
},
},
name: 'stepHeight',
setter: {
componentName: 'NumberSetter',
isRequired: true,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'borderRadius',
'zh-CN': '圆角',
},
},
name: 'borderRadius',
setter: {
componentName: 'NumberSetter',
isRequired: true,
initialValue: 2,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'percent',
'zh-CN': '进度',
},
},
name: 'percent',
setter: {
componentName: 'NumberSetter',
isRequired: true,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'strokeColor',
'zh-CN': '进度颜色',
},
},
name: 'strokeColor',
setter: {
componentName: 'ColorSetter',
isRequired: false,
initialValue: '#1890ff',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'trailColor',
'zh-CN': '底层颜色',
},
},
name: 'trailColor',
setter: {
componentName: 'ColorSetter',
isRequired: false,
initialValue: '#f0f0f0',
},
},
]
},
{
name: 'legend',
type: 'group',
display: 'accordion',
title: {
label: '气泡提示',
},
items: [
{
title: {
label: {
type: 'i18n',
'en-US': 'isBalloon',
'zh-CN': '显隐',
},
},
name: 'isBalloon',
setter: {
componentName: 'BoolSetter',
isRequired: false,
initialValue: true,
},
},
]
},
{
name: 'legend',
type: 'group',
display: 'accordion',
title: {
label: 'label',
},
items: [
{
title: {
label: {
type: 'i18n',
'en-US': 'labelText',
'zh-CN': '内容',
},
},
name: 'labelText',
setter: {
componentName: 'StringSetter',
isRequired: false,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'labelColor',
'zh-CN': '颜色',
},
},
name: 'labelColor',
setter: {
componentName: 'ColorSetter',
isRequired: false,
initialValue: '#000',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'labelSize',
'zh-CN': '字号',
},
},
name: 'labelSize',
setter: {
componentName: 'NumberSetter',
isRequired: false,
initialValue: 16,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'labelBlod',
'zh-CN': '加粗',
},
},
name: 'labelBlod',
setter: {
componentName: 'BoolSetter',
isRequired: false,
initialValue: false,
},
},
]
},
{
name: 'legend',
type: 'group',
display: 'accordion',
title: {
label: '百分比',
},
items: [
{
title: {
label: {
type: 'i18n',
'en-US': 'percentageColor',
'zh-CN': '颜色',
},
},
name: 'percentageColor',
setter: {
componentName: 'ColorSetter',
isRequired: false,
initialValue: '#000',
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'percentageSize',
'zh-CN': '字号',
},
},
name: 'percentageSize',
setter: {
componentName: 'NumberSetter',
isRequired: false,
initialValue: 16,
},
},
{
title: {
label: {
type: 'i18n',
'en-US': 'percentageBlod',
'zh-CN': '加粗',
},
},
name: 'percentageBlod',
setter: {
componentName: 'BoolSetter',
isRequired: false,
initialValue: false,
},
},
]
},
],
component: {},
},
};
const snippets: IPublicTypeSnippet[] = [
{
title: '进度条',
screenshot: '',
schema: {
componentName: 'ProgressSteps',
props: {
width: '400px',
height: '60px',
steps: 10,
stepWidth: 30,
stepHeight: 50,
percent: 50,
strokeColor: '#1890ff',
trailColor: '#f0f0f0',
labelText: 'label',
labelColor: '#000',
labelSize: 16,
labelBlod: false,
percentageColor: '#000',
percentageSize: 16,
percentageBlod: false,
},
},
},
];
export default {
...ProgressStepsMeta,
snippets,
};