如何实现点击应用按钮时才触发combineLatest执行多条件产品筛选
实现点击“应用”按钮才触发RxJS筛选的方案
核心思路很简单:我们需要把实时更新的筛选条件先暂存起来,不再让combineLatest实时响应每个复选框的变化,而是只在用户点击“应用”按钮时,才触发一次筛选逻辑。
步骤1:重构筛选条件的存储方式
原来的productFilterApplied$这类Subject是用来实时推送筛选变化的,现在我们换成普通变量来暂存用户的选择,直到点击应用才生效:
// 用普通数组/变量暂存筛选条件,替代原来的Subject private productFilters: string[] = []; private collectionFilters: string[] = []; private statusFilters: string[] = []; private unitPriceFilter: string = ''; private markUpFilter: string = ''; // 创建一个专门用来触发筛选的Subject private applyFilterTrigger$ = new Subject<void>(); // 最终的筛选结果Observable(后续重构) filteredProduct$: Observable<any[]>;
步骤2:修改复选框的事件处理逻辑
原来的productChanged方法会直接更新Subject,现在改成只修改暂存的变量,不触发筛选:
public productChanged(filterValue: any) { if (filterValue.name != undefined) { const idx = this.productFilters.indexOf(filterValue.name); if (idx >= 0) { this.productFilters.splice(idx, 1); } else { this.productFilters.push(filterValue.name); } // 这里不再调用Subject.next(),只是更新本地暂存的筛选条件 } }
其他类似的
collectionChanged、statusChanged等方法,都按照这个逻辑修改,只更新对应的暂存变量即可。
步骤3:添加“应用”按钮的点击事件
点击按钮时,通过applyFilterTrigger$发送信号,触发筛选:
public onApplyFilters() { this.applyFilterTrigger$.next(); }
步骤4:重构筛选逻辑的Observable
现在我们不再用combineLatest监听所有筛选条件的实时变化,而是通过applyFilterTrigger$的信号,结合最新的产品数据和暂存的筛选条件来执行筛选:
this.filteredProduct$ = this.applyFilterTrigger$.pipe( // 每次触发筛选时,获取最新的产品数据 withLatestFrom(this.productDataList$), map(([_, products]) => { // 复制原数组,避免修改原始数据 let filtered = [...products]; // 产品类型筛选 if (this.productFilters.length) { filtered = filtered.filter(product => this.productFilters.includes(product.productType)); } // 收藏集筛选 if (this.collectionFilters.length) { filtered = filtered.filter(product => this.collectionFilters.includes(product.collections)); } // 状态筛选 if (this.statusFilters.length) { filtered = filtered.filter(product => this.statusFilters.includes(product.downstreamStatus)); } // 单价筛选(优化成switch更简洁) if (this.unitPriceFilter && this.unitPriceFilter !== 'clear') { switch (this.unitPriceFilter) { case "0-100": filtered = filtered.filter(item => { const price = Math.round(item?.unitPriceWithShippingFee); return price >= 0 && price <= 100; }); break; case "100-500": filtered = filtered.filter(item => { const price = Math.round(item?.unitPriceWithShippingFee); return price >= 100 && price <= 500; }); break; case "500-1000": filtered = filtered.filter(item => { const price = Math.round(item?.unitPriceWithShippingFee); return price >= 500 && price <= 1000; }); break; case "1000 and above": filtered = filtered.filter(item => Math.round(item?.unitPriceWithShippingFee) >= 1000); break; } } // Markup筛选(同样优化成switch) if (this.markUpFilter && this.markUpFilter !== 'clear') { switch (this.markUpFilter) { case "0-25 (%)": filtered = filtered.filter(item => { const markup = Math.round(item?.markup); return markup >= 0 && markup <= 25; }); break; case "25-50 (%)": filtered = filtered.filter(item => { const markup = Math.round(item?.markup); return markup >= 25 && markup <= 50; }); break; case "50-75 (%)": filtered = filtered.filter(item => { const markup = Math.round(item?.markup); return markup >= 50 && markup <= 75; }); break; case "75-100 (%)": filtered = filtered.filter(item => { const markup = Math.round(item?.markup); return markup >= 75 && markup <= 100; }); break; } } return filtered; }) ); // 组件销毁时记得清理Subject,避免内存泄漏 ngOnDestroy() { this.applyFilterTrigger$.complete(); }
额外优化建议
可以把每个筛选逻辑拆成单独的工具函数,让代码更易维护:
private filterByProductType(products: any[], filters: string[]) { return filters.length ? products.filter(p => filters.includes(p.productType)) : products; } private filterByUnitPrice(products: any[], filter: string) { if (!filter || filter === 'clear') return products; const priceRanges: Record<string, [number, number?]> = { "0-100": [0, 100], "100-500": [100, 500], "500-1000": [500, 1000], "1000 and above": [1000] }; const [min, max] = priceRanges[filter]; return products.filter(item => { const price = Math.round(item?.unitPriceWithShippingFee); return max ? price >= min && price <= max : price >= min; }); }
这样在主逻辑里就可以简化成:
let filtered = [...products]; filtered = this.filterByProductType(filtered, this.productFilters); filtered = this.filterByUnitPrice(filtered, this.unitPriceFilter); // ...其他筛选逻辑
内容的提问来源于stack exchange,提问作者Kumaravel A
相关产品推荐
相关产品推荐

