筛选组件开发

This commit is contained in:
juguohong
2025-08-17 18:36:43 +08:00
parent 4f6ca73148
commit db48e55b05
17 changed files with 406 additions and 314 deletions

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import './index.scss';
import BubbleItem from './BubbleItem';
import React, { useState, useEffect } from "react";
import styles from "./index.module.scss";
import BubbleItem from "./BubbleItem";
export interface BubbleOption {
id: string | number;
@@ -14,12 +14,16 @@ export interface BubbleOption {
export interface BubbleProps {
options: BubbleOption[];
value?: string | number | (string | number)[];
onChange?: (value: string | number | (string | number)[], option: BubbleOption | BubbleOption[]) => void;
onChange?: (
value: string | number | (string | number)[],
option: BubbleOption | BubbleOption[]
) => void;
multiple?: boolean;
layout?: 'horizontal' | 'vertical' | 'grid';
layout?: "horizontal" | "vertical" | "grid";
columns?: number;
size?: 'small' | 'medium' | 'large';
size?: "small" | "medium" | "large";
className?: string;
itemClassName?: string;
style?: React.CSSProperties;
disabled?: boolean;
}
@@ -29,12 +33,13 @@ const Bubble: React.FC<BubbleProps> = ({
value,
onChange,
multiple = false,
layout = 'horizontal',
layout = "horizontal",
columns = 3,
size = 'small',
className = '',
size = "small",
className = "",
itemClassName = "",
style = {},
disabled = false
disabled = false,
}) => {
const [selectedValues, setSelectedValues] = useState<(string | number)[]>([]);
@@ -53,7 +58,7 @@ const Bubble: React.FC<BubbleProps> = ({
if (multiple) {
if (selectedValues.includes(option.value)) {
newSelectedValues = selectedValues.filter(v => v !== option.value);
newSelectedValues = selectedValues.filter((v) => v !== option.value);
} else {
newSelectedValues = [...selectedValues, option.value];
}
@@ -62,11 +67,13 @@ const Bubble: React.FC<BubbleProps> = ({
}
setSelectedValues(newSelectedValues);
// 调用onChange回调传递选中的值和对应的选项
if (onChange) {
if (multiple) {
const selectedOptions = options.filter(opt => newSelectedValues.includes(opt.value));
const selectedOptions = options.filter((opt) =>
newSelectedValues.includes(opt.value)
);
onChange(newSelectedValues, selectedOptions);
} else {
onChange(option.value, option);
@@ -79,7 +86,7 @@ const Bubble: React.FC<BubbleProps> = ({
};
const renderHorizontalLayout = () => (
<div className="bubble-horizontal">
<div className={styles.bubbleHorizontal}>
{options.map((option) => (
<BubbleItem
key={option.id}
@@ -88,13 +95,14 @@ const Bubble: React.FC<BubbleProps> = ({
size={size}
disabled={disabled}
onClick={handleOptionClick}
itemClassName={itemClassName}
/>
))}
</div>
);
const renderVerticalLayout = () => (
<div className="bubble-vertical">
<div className={styles.bubbleVertical}>
{options.map((option) => (
<BubbleItem
key={option.id}
@@ -103,17 +111,18 @@ const Bubble: React.FC<BubbleProps> = ({
size={size}
disabled={disabled}
onClick={handleOptionClick}
itemClassName={itemClassName}
/>
))}
</div>
);
const renderGridLayout = () => (
<div
className="bubble-grid"
style={{
<div
className={styles.bubbleGrid}
style={{
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: size === 'small' ? '8px' : size === 'large' ? '16px' : '12px'
gap: size === "small" ? "8px" : size === "large" ? "16px" : "12px",
}}
>
{options.map((option) => (
@@ -124,6 +133,7 @@ const Bubble: React.FC<BubbleProps> = ({
size={size}
disabled={disabled}
onClick={handleOptionClick}
itemClassName={itemClassName}
/>
))}
</div>
@@ -131,11 +141,11 @@ const Bubble: React.FC<BubbleProps> = ({
const renderLayout = () => {
switch (layout) {
case 'horizontal':
case "horizontal":
return renderHorizontalLayout();
case 'vertical':
case "vertical":
return renderVerticalLayout();
case 'grid':
case "grid":
return renderGridLayout();
default:
return renderHorizontalLayout();
@@ -143,7 +153,7 @@ const Bubble: React.FC<BubbleProps> = ({
};
return (
<div className={`bubble-container ${className}`} style={style}>
<div className={`${styles.bubbleContainer} ${className}`} style={style}>
{renderLayout()}
</div>
);