javascript
import React from 'react';
import styles from './index.module.less';
type OptionsType = {
/**
* 每个item渲染一行,第0项为标题
*/
labels?: any[];
/**
* 自定义渲染内容
*/
label?: string | React.ReactNode;
value: any;
};
interface IProps {
value?: any;
onChange?: Function;
options: OptionsType[];
layout?: 'horizontal' | 'vertical';
disabled?: boolean;
}
export default function Index(props: IProps) {
const { value, onChange = () => {}, options, layout = 'horizontal', disabled = false } = props;
const clickHandler = (row) => {
if (disabled) return;
if (value === row.value) {
onChange(undefined);
} else {
onChange(row.value);
}
};
return (
<div className={`${styles.container} ${styles[layout]}`}>
{options?.map((item, index) => {
const activeStyles = item.value === value ? styles['select-card-checked'] : styles['select-card'];
const disabledStyles = disabled ? styles['select-card-disabled'] : '';
return (
<div key={index} className={`${activeStyles} ${disabledStyles}`.trim()} onClick={() => clickHandler(item)}>
<div className={styles.corner}></div>
<div className={styles.content}>
{item?.label
? item?.label
: item?.labels?.map((v, idx) => {
return (
<React.Fragment key={idx}>
{idx === 0 && v ? (
<div className={styles.title}>{v}</div>
) : (
<div className={styles.text}>{v}</div>
)}
</React.Fragment>
);
})}
</div>
</div>
);
})}
</div>
);
}
css
@primaric-color: #5050e6;
@primary-color-opacity: #5050e680;
.container {
.select-card {
position: relative;
width: 300px;
padding: 14px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
border: 1px solid #f9f9f9;
background-color: #fff;
cursor: pointer;
margin: 0 14px 14px 0;
.corner {
position: absolute;
top: 2px;
right: 2px;
width: 0;
height: 0;
border-top: 12px solid #5050e6;
border-left: 12px solid transparent;
border-radius: 0 3px 0 0;
opacity: 0;
}
.content {
.title {
margin: 0;
font-size: 15px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.title:nth-last-of-type(1) {
margin-bottom: 0;
}
.text {
margin-bottom: 10px;
font-size: 14px;
color: #666;
}
.text:nth-last-of-type(1) {
margin-bottom: 0;
}
}
}
.select-card:hover {
border-color: @primary-color-opacity;
box-shadow: 0 0 3px 0 @primaric-color;
}
.select-card:nth-last-of-type(1) {
margin: 0;
}
.select-card-checked {
position: relative;
width: 300px;
padding: 14px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
border: 1px solid @primary-color-opacity;
background-color: #f0f2ff;
cursor: pointer;
margin: 0 14px 14px 0;
box-shadow: 0 0 3px 0 @primaric-color;
.corner {
position: absolute;
top: 2px;
right: 2px;
width: 0;
height: 0;
border-top: 12px solid @primaric-color;
border-left: 12px solid transparent;
border-radius: 0 3px 0 0;
opacity: 1;
}
.content {
.title {
margin: 0;
font-size: 15px;
font-weight: bold;
margin-bottom: 10px;
}
.title:nth-last-of-type(1) {
margin-bottom: 0;
}
.text {
margin-bottom: 10px;
font-size: 14px;
color: #666;
}
.text:nth-last-of-type(1) {
margin-bottom: 0;
}
}
}
.select-card-checked:nth-last-of-type(1) {
margin: 0;
}
.select-card-disabled {
background-color: #e0e0e0;
border-color: #a0a0a0;
color: #666;
box-shadow: none;
cursor: not-allowed;
.corner {
border-top-color: #a0a0a0;
}
}
}
.horizontal {
}
.vertical {
display: flex;
flex-wrap: wrap;
}