草写一个按钮样式的多选框组件

546 阅读1分钟

最新的项目需求中 UI 设计了一个按钮样式的多选框,选中之后在按钮右上角有一个白色对勾,表示选中状态;之后在 Antd 内查看组件文档,发现没有这个状态的复选框,无奈,只能自己写了;

耗时半小时,简单写了一下,能满足需求,不过如果想作为一个比较完善的公共组件,有一些地方需要去细化一下,考虑不同情况,比如 options 数据格式的校验、组件样式的传递、以及代码优化等等;

下面是代码,首先是组件本体

// 按钮状态的多选框
import React, { useState } from 'react';
import { Space } from 'antd';

const CheckButtonGroup = (props) => {
const [value, setValue] = useState({});
const { options } = props;


const handleChange = (index, selected) => {
    const newValue = value;
    if (selected) {
        newValue[index] = options[index].value;
    } else {
        newValue[index] = '';
    }
    setValue(newValue);
    const propsValue: string[] = [];
    Object.keys(newValue).forEach((key) => {
        if (newValue[key]) {
            propsValue.push(newValue[key]);
        }
    });
    props.onChange?.(propsValue);
};

return (
    <div>
        <Space size={20} wrap>
            {options.map((op, index) => (
                <CheckButton key={op.value} onClick={handleChange} index={index}>
                    {op.label}
                </CheckButton>
            ))}
        </Space>
    </div>
 );
};

这个组件用到了另一个组件,此组件是按钮的本体

import React, { useState } from 'react';
import classNames from 'classnames';
import styles from './index.module.less';

const CheckButton = (props) => {

const [isSelected, setSelected] = useState(false);
const handleClick = () => {
    props.onClick(props.index, !isSelected);
    setSelected(!isSelected);
};

return (
    <span
        className={classNames(styles.default, {
            [styles.selected]: isSelected,
        })}
        onClick={handleClick}
    >
        <span>{props.children}</span>
    </span>
 );
};

组件样式

.default {
    display: inline-block;
    padding: 10px 24px;
    border: 1px solid #C8C8C8;
    color: #212223;
    border-radius: 4px;
}

.selected {
    border: 1px solid #017EFA;
    color: #017EFA;
    position: relative;

    &:before {
        content: "";
        position: absolute;
        right: 0;
        top: 0;
        border: 10px solid #017EFA;
        border-bottom-color: transparent;
        border-left-color: transparent;
    }

    &:after {
        content: "";
        width: 3px;
        height: 6px;
        position: absolute;
        right: 3px;
        top: 0;
        border: 1px solid #fff;
        border-top-color: transparent;
        border-left-color: transparent;
        transform: rotate(45deg);
    }
}
    

组件使用

<CheckButtonGroup
    options={[
        { label: '测试多选', value: 'time' },
        { label: '按钮样式', value: 'position' },
        { label: '多选框', value: 'name' },
        { label: '看效果', value: 'type' },
        { label: '还可以', value: 'level' },
        { label: '改样式', value: 'source' },
    ]}

    onChange={(value) => {
        console.log(value);
    }}
/>

组件效果

图片.png

写的比较粗糙,若有错误可指出,改不改的那就看情况了;