Nuxt3中使用$fetch时如何处理空数组参数及过滤器重置
问题
我正在用Nuxt3搭建带过滤器和搜索框的搜索界面,目前通过$fetch携带参数调用API的代码如下:
const { data: cheeses, refresh } = await useAsyncData('cheeses', () => $fetch("/api/v1/cheese", { params: { name: modele.value.name, regions: JSON.stringify(modele.value.regions), curd_types: JSON.stringify(modele.value.curd_types), milk_types: JSON.stringify(modele.value.milk_types), aoc: modele.value.aoc } }) );
后端自定义API中,我通过获取这些参数来构建Supabase查询:
export default eventHandler(async (event) => { const client = serverSupabaseClient(event); // 获取请求参数 const query = await getQuery(event) const filterByName = query.name; const filterByRegion = query.regions; const filterByCurdType = query.curd_types; const filterByMilkType = query.milk_types; const filterByAOC = query.aoc; // 初始化查询 let querySupabase = client.from('cheeses').select() // 根据参数应用过滤条件 if (filterByName) { querySupabase = querySupabase.ilike('name', '%' + filterByName + '%') } if (filterByAOC) { querySupabase = querySupabase.eq('aoc', filterByAOC) } if (filterByRegion) { const regions = JSON.parse(filterByRegion) querySupabase = querySupabase.overlaps('regions', regions) } if (filterByCurdType) { const curd_types = JSON.parse(filterByCurdType) querySupabase = querySupabase.overlaps('curd_type', curd_types) } if (filterByMilkType) { const milk_types = JSON.parse(filterByMilkType) querySupabase = querySupabase.overlaps('milk_types', milk_types) } // 执行查询并排序 const { data, error } = await querySupabase .order("name", { ascending: true }); // 错误处理 if (error !== null){ return error } else { return data } })
搜索页里有多个多选过滤器(选中项存在数组里),通过v-model和名为modele的响应式对象绑定,功能正常,但过滤器重置的逻辑一直没处理好。我试过两种方案:
- 删除
modele的所有属性后更新查询:
async function reinitializeFilters() { for (const [key, value] of Object.entries(modele.value)) { delete modele.value[key]; } await updateQuery(); }
这种方式能清空modele和查询参数,但页面上的组件选中状态没同步清空。
2. 把modele所有属性设为null后更新查询:
async function reinitializeFilters() { for (const [key, value] of Object.entries(modele.value)) { modele.value[key] = null; } await updateQuery(); }
这种方式能重置页面组件的选中状态,但JSON.stringify(null)会导致后端查询报错。
想请教下,处理这类包含数组类型的查询参数时,过滤器重置函数的最佳实践是什么?
解决方案
核心思路
要同时满足页面组件选中状态同步重置和后端不接收无效null参数两个要求,需要从前端重置逻辑、请求参数处理、后端参数校验三个层面优化:
- 定义标准初始状态模板
给modele明确初始值,不同类型字段对应合适的默认值:字符串用空串,数组用空数组,枚举/布尔类型用null,保证类型一致性:
const DEFAULT_FILTERS = { name: '', regions: [], curd_types: [], milk_types: [], aoc: null } const modele = ref({...DEFAULT_FILTERS})
- 重置函数直接还原初始状态
重置时将modele赋值为初始状态的深拷贝,既触发Vue响应式更新同步页面组件,又保证参数类型正确:
async function reinitializeFilters() { // 深拷贝避免引用关联问题 modele.value = JSON.parse(JSON.stringify(DEFAULT_FILTERS)); // 直接用useAsyncData返回的refresh方法刷新查询 await refresh(); }
- 前端自动过滤无效请求参数
在$fetch的params中自动过滤空串、空数组、null这类无效值,避免传给后端:
const { data: cheeses, refresh } = await useAsyncData('cheeses', () => $fetch("/api/v1/cheese", { params: Object.fromEntries( Object.entries(modele.value).filter(([key, val]) => { // 过滤规则:空串、空数组、null都不传递 if (typeof val === 'string') return val.trim() !== ''; if (Array.isArray(val)) return val.length > 0; return val !== null; }).map(([key, val]) => { // 数组类型参数转JSON字符串 return [key, Array.isArray(val) ? JSON.stringify(val) : val]; }) ) }) );
- 后端增强参数容错处理
在API端增加参数解析的容错逻辑,避免单个参数异常导致整个查询失败:
export default eventHandler(async (event) => { const client = serverSupabaseClient(event); const query = await getQuery(event); let querySupabase = client.from('cheeses').select(); // 名称过滤:仅处理非空有效字符串 if (query.name && typeof query.name === 'string' && query.name.trim()) { querySupabase = querySupabase.ilike('name', `%${query.name.trim()}%`); } // AOC过滤:仅处理非null的有效值 if (query.aoc !== null && query.aoc !== undefined) { querySupabase = querySupabase.eq('aoc', query.aoc); } // 封装数组类型参数的统一处理函数 const handleArrayFilter = (paramKey, dbField) => { if (!query[paramKey]) return; try { const arr = JSON.parse(query[paramKey]); if (Array.isArray(arr) && arr.length > 0) { querySupabase = querySupabase.overlaps(dbField, arr); } } catch (e) { // 解析失败时忽略该过滤条件,不中断整个查询 console.error(`解析${paramKey}参数失败`, e); } }; // 应用各数组类型过滤条件 handleArrayFilter('regions', 'regions'); handleArrayFilter('curd_types', 'curd_type'); handleArrayFilter('milk_types', 'milk_types'); const { data, error } = await querySupabase.order("name", { ascending: true }); if (error) { console.error('Supabase查询错误', error); return createError({ statusCode: 500, statusMessage: '查询失败' }); } return data; })
方案优势
- 明确的初始状态避免了重置后的类型混乱;
- 深拷贝重置完美同步页面组件的响应式状态;
- 前端过滤无效参数减少了无效请求,降低后端校验压力;
- 后端容错处理提升了接口稳定性,避免单个参数异常导致整个查询失败。
内容的提问来源于stack exchange,提问作者Hibar84
相关产品推荐
相关产品推荐

