You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的响应式对象绑定,功能正常,但过滤器重置的逻辑一直没处理好。我试过两种方案:

  1. 删除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参数两个要求,需要从前端重置逻辑、请求参数处理、后端参数校验三个层面优化:

  1. 定义标准初始状态模板
    给modele明确初始值,不同类型字段对应合适的默认值:字符串用空串,数组用空数组,枚举/布尔类型用null,保证类型一致性:
const DEFAULT_FILTERS = {
  name: '',
  regions: [],
  curd_types: [],
  milk_types: [],
  aoc: null
}
const modele = ref({...DEFAULT_FILTERS})
  1. 重置函数直接还原初始状态
    重置时将modele赋值为初始状态的深拷贝,既触发Vue响应式更新同步页面组件,又保证参数类型正确:
async function reinitializeFilters() {
  // 深拷贝避免引用关联问题
  modele.value = JSON.parse(JSON.stringify(DEFAULT_FILTERS));
  // 直接用useAsyncData返回的refresh方法刷新查询
  await refresh();
}
  1. 前端自动过滤无效请求参数
    在$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];
      })
    )
  })
);
  1. 后端增强参数容错处理
    在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 01:55:11