index.tsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import { useEffect, useRef, useState } from 'react';
  2. import classNames from 'classnames';
  3. import { isArray } from 'lodash';
  4. import './index.less';
  5. import { CheckOutlined } from '@ant-design/icons';
  6. type RadioCardModelType = 'multiple' | 'singular';
  7. interface RadioCardItem {
  8. label: string;
  9. value: string;
  10. imgUrl: string;
  11. }
  12. export interface RadioCardProps {
  13. value?: string | string[];
  14. model?: RadioCardModelType;
  15. options: RadioCardItem[];
  16. onChange?: (keys: string | string[]) => void;
  17. onSelect?: (key: string, selected: boolean, node: RadioCardItem[]) => void;
  18. }
  19. export default (props: RadioCardProps) => {
  20. const { value, model, options, onChange, onSelect } = props;
  21. const [keys, setKeys] = useState<string[]>([]);
  22. const isMultiple = useRef<boolean>(true);
  23. isMultiple.current = !(model && model === 'singular');
  24. useEffect(() => {
  25. // 初始化
  26. setKeys(value ? (isArray(value) ? value : [value]) : []);
  27. }, [props.value]);
  28. const getNode = (_keys: string[]) =>
  29. options.filter((item) => _keys.some((key) => key === item.value));
  30. const toggleOption = (key: string) => {
  31. const optionIndex = keys.indexOf(key);
  32. const newKeys = [...keys];
  33. if (optionIndex === -1) {
  34. if (isMultiple.current) {
  35. newKeys.push(key);
  36. } else {
  37. newKeys[0] = key;
  38. }
  39. } else {
  40. newKeys.splice(optionIndex, 1);
  41. }
  42. if (!('value' in props)) {
  43. setKeys(newKeys);
  44. }
  45. if (onChange) {
  46. onChange(isMultiple.current ? newKeys : newKeys[0]);
  47. }
  48. if (onSelect) {
  49. onSelect(key, optionIndex === -1, getNode(newKeys));
  50. }
  51. };
  52. return (
  53. <div className={'radio-card-items'}>
  54. {options.map((item) => {
  55. return (
  56. <div
  57. className={classNames('radio-card-item', {
  58. checked: keys?.includes(item.value),
  59. })}
  60. key={item.value}
  61. onClick={() => {
  62. toggleOption(item.value);
  63. }}
  64. >
  65. <img width={32} height={32} src={item.imgUrl} alt={''} />
  66. <span>{item.label}</span>
  67. <div className={'checked-icon'}>
  68. <div>
  69. <CheckOutlined />
  70. </div>
  71. </div>
  72. </div>
  73. );
  74. })}
  75. </div>
  76. );
  77. };