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

Vue3组合式API异步代码处理与搜索过滤问题求助

Vue3组合式API异步数据过滤问题解决

问题原因

你遇到的quote.includes is not a function错误,本质是你在对对象调用字符串的includes方法。从json-server获取的quotes是对象数组(每个quote是包含tags等属性的对象),而不是字符串数组,直接调用quote.includes()自然会报错。

另外,虽然computed会自动响应数据变化,但初始异步加载还没完成时quotes是空数组,不过这不是报错的核心原因——核心是对象没有includes方法。

解决方案

1. 修正过滤逻辑,指定具体字段匹配

你需要明确要匹配quote对象中的哪个字段(比如假设你的quote对象有content或text字段,你需要根据实际JSON结构调整)。比如如果要匹配quote的内容:

const matchingQuotes = computed(() => {
  // 如果搜索关键词为空,返回所有quotes
  if (!search.value.trim()) return quotes.value;
  // 转成小写,实现不区分大小写的匹配
  const keyword = search.value.toLowerCase();
  return quotes.value.filter(quote => {
    // 这里替换成你实际要匹配的字段,比如quote.text、quote.content
    return quote.content.toLowerCase().includes(keyword);
  });
});

2. 优化模板渲染

你现在模板里同时渲染了原始quotes和matchingQuotes,这会导致重复内容。建议只渲染过滤后的结果:

<template>
  <div>
    <h1>Home</h1>
    <input type="text" v-model="search" placeholder="搜索语录">
    <p>搜索关键词 - {{ search }}</p>
    <!-- 只渲染过滤后的结果 -->
    <div v-for="quote in matchingQuotes" :key="quote.id">
      {{ quote.content }} <!-- 替换成你实际要展示的字段 -->
      <small>标签:{{ quote.tags.join(', ') }}</small>
    </div>
  </div>
</template>

3. (可选)添加加载状态

因为数据是异步获取的,可以加个加载提示提升体验:

// 在setup里添加加载状态ref
const isLoading = ref(true);

const load = async () => {
  try {
    let response = await fetch('http://localhost:3000/quotes')
    let rawData = await response.json()
    quotes.value = rawData

    rawData.forEach(quoteObject => {
      quoteObject.tags.forEach(tag => tagSet.add(tag))
    });
    tags.value = [...tagSet]
  } catch (err) {
    console.error('加载数据失败:', err)
  } finally {
    isLoading.value = false;
  }
}
load()

模板里添加加载提示:

<template>
  <div>
    <h1>Home</h1>
    <input type="text" v-model="search" placeholder="搜索语录" :disabled="isLoading">
    <p>搜索关键词 - {{ search }}</p>

    <div v-if="isLoading">加载中...</div>
    <div v-else v-for="quote in matchingQuotes" :key="quote.id">
      {{ quote.content }}
      <small>标签:{{ quote.tags.join(', ') }}</small>
    </div>
  </div>
</template>

完整修正代码

<template>
  <div>
    <h1>Home</h1>
    <input type="text" v-model="search" placeholder="搜索语录" :disabled="isLoading">
    <p>搜索关键词 - {{ search }}</p>

    <div v-if="isLoading">加载中...</div>
    <div v-else v-for="quote in matchingQuotes" :key="quote.id">
      {{ quote.content }}
      <small style="margin-left: 10px;">标签:{{ quote.tags.join(', ') }}</small>
    </div>
  </div>
</template>

<script>
import { computed, ref } from 'vue';
export default {
  name: 'Home',
  setup() {
    const search = ref('')
    const quotes = ref([])
    const tags = ref([])
    const tagSet = new Set()
    const isLoading = ref(true)

    const load = async () => {
      try {
        const response = await fetch('http://localhost:3000/quotes')
        const rawData = await response.json()
        quotes.value = rawData

        rawData.forEach(quoteObject => {
          quoteObject.tags.forEach(tag => tagSet.add(tag))
        });
        tags.value = [...tagSet]
      } catch (err) {
        console.error('加载数据出错:', err)
      } finally {
        isLoading.value = false
      }
    }
    load()

    const matchingQuotes = computed(() => {
      if (!search.value.trim()) return quotes.value
      const keyword = search.value.toLowerCase()
      return quotes.value.filter(quote => {
        // 这里替换成你实际要匹配的字段,比如quote.text
        return quote.content.toLowerCase().includes(keyword)
      })
    })

    return {
      quotes,
      search,
      matchingQuotes,
      isLoading
    }
  },
}
</script>

关键注意点

  • 一定要根据你的json-server返回的quote对象结构,替换代码中quote.content为实际字段(比如quote.text、quote.quote等)。
  • 初始空数组的情况已经被computed处理了,因为空数组filter后还是空数组,不会报错。
  • 添加trim()处理搜索关键词,避免空输入时的无效匹配。

内容的提问来源于stack exchange,提问作者gunjag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 20:25:11