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
相关产品推荐
相关产品推荐

