JS/React如何实现多组复选框联动过滤数组,支持多维度联合筛选
多筛选条件联动实现方案
核心改造思路
将原代码的单字段筛选逻辑调整为支持多字段可配置的通用筛选逻辑,不同筛选字段的状态独立管理,最终过滤时所有字段的条件同时生效(逻辑与关系)。
核心改动点
- 预定义需要支持筛选的字段列表,后续新增筛选字段只需在列表中追加对应字段名即可
- 筛选状态按字段分组存储,每个字段独立维护自身的选项列表与全选状态
- 复选框绑定所属字段标识,触发变更时可精准定位到对应筛选组更新状态
- 最终过滤逻辑遍历所有筛选字段,只有同时满足所有激活条件的条目才会被展示
完整实现代码
const Item = ({ title }) => <div><h4>{title}</h4></div>; const Filter = ({ field, value, active, onChange }) => ( <label className="filter" style={{ marginRight: '12px' }}> <input type="checkbox" checked={active} data-field={field} data-value={value} onChange={onChange} /> {value} </label> ); // 定义需要支持筛选的字段,新增筛选字段直接追加即可 const FILTER_FIELDS = ['brand', 'series']; // 可配置字段对应的展示名称 const FIELD_LABELS = { brand: '品牌', series: '系列' }; function App({ items }) { const [filters, setFilters] = React.useState({}); React.useEffect(() => { const initFilters = {}; FILTER_FIELDS.forEach(field => { // 生成当前字段的去重选项,追加全选项 const fieldValues = [...new Set(['all', ...items.map(n => n[field])])]; initFilters[field] = fieldValues.map((value, i) => ({ active: value === 'all', // 默认全选激活 value, id: `${field}-${i}` })); }); setFilters(initFilters); }, [items]); const onFilterChange = ({ target: { checked: active, dataset: { field, value } } }) => { const currentFieldFilters = filters[field]; let newFieldFilters; if (value === 'all') { // 点击全选:同步更新当前字段所有选项的选中状态 newFieldFilters = currentFieldFilters.map(item => ({ ...item, active })); } else { // 点击普通选项:更新当前选项状态,同时自动同步全选状态 newFieldFilters = currentFieldFilters.map(item => item.value === value ? { ...item, active } : item ); const isAllSelected = newFieldFilters .filter(item => item.value !== 'all') .every(item => item.active); newFieldFilters.find(item => item.value === 'all').active = isAllSelected; } setFilters({ ...filters, [field]: newFieldFilters }); }; // 多条件联动过滤 const filteredItems = items.filter(item => { // 遍历所有筛选字段,所有条件都满足才返回true return FILTER_FIELDS.every(field => { const activeValues = filters[field]?.filter(f => f.active).map(f => f.value) || []; // 全选激活 或 选项包含当前item的对应字段值,则条件通过 return activeValues.includes('all') || activeValues.includes(item[field]); }); }); return ( <div style={{ padding: '20px' }}> {/* 渲染所有筛选组 */} {Object.keys(filters).map(field => ( <div key={field} style={{ marginBottom: '12px' }}> <strong>{FIELD_LABELS[field]}:</strong> {filters[field].map(filter => ( <Filter key={filter.id} field={field} {...filter} onChange={onFilterChange} /> ))} </div> ))} <div style={{ marginTop: '24px' }}> {filteredItems.map(n => <Item key={n.id} {...n} />)} </div> </div> ); } const Items = [ { brand: 'Acer', title: 'Acer 1', series: "1" }, { brand: 'Acer', title: 'Acer 2', series: "1" }, { brand: 'Asus', title: 'Asus 1', series: "3" }, { brand: 'Acer', title: 'Acer 3', series: "1" }, { brand: 'Apple', title: 'Apple 1', series: "3" }, { brand: 'Acer', title: 'Acer 4', series: "3" }, { brand: 'Apple', title: 'Apple 2', series: "1" }, { brand: 'Asus', title: 'Asus 2', series: "2" }, { brand: 'Asus', title: 'Asus 3', series: "2" }, { brand: 'Acer', title: 'Acer 5', series: "2" }, { brand: 'Apple', title: 'Apple 3', series: "2" }, ].map((n, i) => ({ ...n, id: i + 1 })); ReactDOM.render(<App items={Items} />, document.getElementById('app'));
扩展说明
如果需要新增其他筛选字段,只需要修改FILTER_FIELDS数组,追加对应的字段名,同时在FIELD_LABELS里添加对应的展示名称即可,无需修改其他逻辑。
内容的提问来源于stack exchange,提问作者Dreamy
相关产品推荐
相关产品推荐

