从零搭建分步筛选式多选项Product Selector的技术问询
从零搭建逐步筛选式产品选择器
1. 先梳理核心逻辑与数据结构
首先得把产品和筛选维度理清楚,参考你需要的层级筛选样式,先明确核心要素:
- 定义筛选层级:比如
步骤1:产品大类→步骤2:产品子类→步骤3:关键参数,层级间要有依赖关系(选了大类才显示对应子类) - 产品数据结构示例(JSON格式):
{ "products": [ { "id": "prod001", "name": "工业接近传感器", "category": "FA", "subCategory": "142", "params": {"防护等级": "IP67", "输出信号": "PNP", "检测距离": "10mm"} } ], "filters": [ { "step": 1, "name": "产品大类", "options": [{"value": "FA", "label": "工厂自动化"}, {"value": "PA", "label": "过程自动化"}] }, { "step": 2, "name": "产品子类", "dependencies": {"FA": ["142", "143"], "PA": ["201", "202"]}, "options": [{"value": "142", "label": "接近传感器"}, {"value": "143", "label": "光电传感器"}] }, { "step": 3, "name": "防护等级", "dependencies": {"142": ["IP65", "IP67"], "143": ["IP66", "IP68"]}, "options": [{"value": "IP67", "label": "IP67"}, {"value": "IP65", "label": "IP65"}] } ] }
2. 前端实现(以React为例,Vue/原生JS逻辑通用)
核心是根据用户选择动态加载下一级选项+实时过滤产品,代码片段如下:
import { useState, useEffect } from 'react'; const ProductSelector = ({ products, filters }) => { const [selected, setSelected] = useState({}); const [currentStep, setCurrentStep] = useState(1); const [matchedProducts, setMatchedProducts] = useState(products); // 选中项变化时,过滤产品 useEffect(() => { let result = [...products]; // 按层级依次过滤 Object.entries(selected).forEach(([stepKey, value]) => { const step = parseInt(stepKey); const filterKey = step === 1 ? 'category' : step === 2 ? 'subCategory' : 'params.防护等级'; result = result.filter(prod => eval(`prod.${filterKey}`) === value); }); setMatchedProducts(result); }, [selected, products]); // 获取当前步骤的可用选项 const getCurrentOptions = () => { const currentFilter = filters.find(f => f.step === currentStep); if (!currentFilter.dependencies) return currentFilter.options; // 根据上一步的选择返回对应选项 const prevValue = selected[currentStep - 1]; return currentFilter.options.filter(opt => currentFilter.dependencies[prevValue]?.includes(opt.value)); }; return ( <div className="product-selector"> {/* 步骤导航栏 */} <div className="step-nav"> {filters.map(filter => ( <button key={filter.step} className={currentStep === filter.step ? 'active' : selected[filter.step] ? 'completed' : ''} onClick={() => setCurrentStep(filter.step)} disabled={!selected[filter.step - 1] && filter.step > 1} > {filter.name} </button> ))} </div> {/* 当前步骤选项区 */} <div className="option-group"> {getCurrentOptions().map(opt => ( <label key={opt.value} className="option-card"> <input type="radio" value={opt.value} checked={selected[currentStep] === opt.value} onChange={(e) => { setSelected({...selected, [currentStep]: e.target.value}); // 非最后一步自动进入下一级 if (currentStep < filters.length) setCurrentStep(currentStep + 1); }} /> <span>{opt.label}</span> </label> ))} </div> {/* 产品结果展示 */} {currentStep === filters.length && ( <div className="product-results"> <h3>匹配产品 ({matchedProducts.length} 个)</h3> <div className="product-list"> {matchedProducts.map(prod => ( <div key={prod.id} className="product-card"> <h4>{prod.name}</h4> <p>防护等级:{prod.params["防护等级"]}</p> <p>检测距离:{prod.params["检测距离"]}</p> </div> ))} </div> </div> )} </div> ); };
3. 样式优化(贴近参考效果)
示例CSS片段,实现步骤进度感、选项卡片化:
.product-selector .step-nav { display: flex; gap: 8px; margin-bottom: 24px; } .step-nav button { padding: 10px 20px; border: 1px solid #ddd; border-radius: 4px; background: #f5f5f5; cursor: pointer; } .step-nav button.active { background: #0066cc; color: white; border-color: #0066cc; } .step-nav button.completed { background: #e8f4f8; border-color: #0066cc; } .step-nav button:disabled { opacity: 0.5; cursor: not-allowed; } .option-group { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 16px; margin-bottom: 32px; } .option-card { display: flex; align-items: center; padding: 16px; border: 1px solid #ddd; border-radius: 8px; cursor: pointer; transition: all 0.2s; } .option-card:hover { border-color: #0066cc; background: #f8fafc; } .option-card input[type="radio"]:checked + span { color: #0066cc; font-weight: 600; } .product-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 20px; } .product-card { padding: 16px; border: 1px solid #eee; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }
4. 后端支持(数据量大时必做)
如果产品数据量过万,前端全量加载会卡顿,需要后端提供接口:
- 接口1:
GET /api/filters?step=1获取第一步筛选选项 - 接口2:
GET /api/filters?step=2&prev=FA根据上一步选择返回对应子类选项 - 接口3:
POST /api/products/filter传入选中的筛选参数,返回匹配的产品列表
示例Node.js/Express路由:
app.get('/api/filters', (req, res) => { const { step, prev } = req.query; // 从数据库查询对应层级的选项 const options = db.query(`SELECT value, label FROM filters WHERE step = ? ${prev ? 'AND prev_value = ?' : ''}`, [step, prev]); res.json(options); }); app.post('/api/products/filter', (req, res) => { const { selected } = req.body; // 构建过滤条件查询产品 const products = db.query(`SELECT * FROM products WHERE category = ? AND sub_category = ? AND protection_level = ?`, [selected[1], selected[2], selected[3]]); res.json(products); });
5. 实用扩展功能
- 重置筛选:添加按钮清空所有选中项,回到第一步
- 多选支持:把单选框改成复选框,过滤逻辑改为包含所有选中值
- URL参数同步:把选中的筛选参数拼到URL(如
?step1=FA&step2=142),支持分享筛选结果 - 搜索补充:在结果区添加产品搜索框,进一步缩小范围
内容的提问来源于stack exchange,提问作者Naveed
相关产品推荐
相关产品推荐

