Vue中计算属性过滤是否覆盖原数组?如何基于API原始数组重过滤?
解决Vue中基于原始数组的响应式过滤问题
嘿,我一眼就看出问题出在哪了——你在过滤的时候直接修改了原始数组里的嵌套属性!
你看这段代码:
feature.properties.site_observations = feature.properties.site_observations.filter(...)
因为数组和对象都是引用类型,这行代码会直接把this.features里的原始site_observations给替换掉。当你清空搜索词再输入新内容时,你过滤的已经是被修改过的数组,而不是API返回的原始数据了,这就导致了错误的结果。
解决思路:不碰原始数据,基于副本处理
我们的核心原则是:永远不要直接修改用于过滤的原始数据源,所有过滤操作都在副本上进行。
方案1:仅筛选出包含匹配项的Feature(不修改Feature内部的观测列表)
如果你只需要把有匹配观测记录的Feature保留下来,不需要修改Feature里的site_observations内容,那可以简化成这样:
filteredFeatures() { // 先处理空搜索词的情况,直接返回原始数组 if (!this.searchTerm.trim()) { return this.features } // 基于原始数组过滤,不修改任何原始数据 return this.features.filter(feature => { // 只检查site_observations是否有匹配项,不修改原数组 const hasMatch = feature.properties.site_observations.some(el => JSON.stringify(el).match(new RegExp(this.searchTerm, 'i')) ) return hasMatch }) }
这里用some替代filter,因为我们只需要知道有没有匹配项,不需要生成新的数组,性能也更好一点。
方案2:筛选Feature同时保留匹配的观测记录
如果你需要在保留Feature的同时,只展示匹配的site_observations,那就要对每个Feature做深拷贝,避免修改原始数据:
filteredFeatures() { if (!this.searchTerm.trim()) { return this.features } return this.features.map(feature => { // 深拷贝Feature对象,彻底和原始数据断开引用 const copiedFeature = JSON.parse(JSON.stringify(feature)) // 在拷贝后的对象上过滤观测记录 copiedFeature.properties.site_observations = copiedFeature.properties.site_observations.filter(el => JSON.stringify(el).match(new RegExp(this.searchTerm, 'i')) ) return copiedFeature }).filter(feature => feature.properties.site_observations.length > 0) }
这里用JSON.parse(JSON.stringify())做深拷贝是最简单的方式,适合没有循环引用的GeoJSON对象。如果你的数据有循环引用,可以用Vue2的Vue.util.extend(true, {}, feature)或者引入lodash的cloneDeep方法。
为什么之前用Object.assign没生效?
因为Object.assign()是浅拷贝,只能复制第一层属性,对于嵌套的site_observations数组,还是会和原始数据共享引用。所以必须用深拷贝才能彻底断开和原始数据的关联。
内容的提问来源于stack exchange,提问作者Peter Donovan
相关产品推荐
相关产品推荐

