Vue3组件通信与搜索结果传递:Composition API方案咨询
Vue3 Composition API 搜索表单问题解答
背景概述
作为Vue3新手,我基于Composition API构建搜索表单:
- 子组件含搜索输入框,触发
doEmitSearch事件并携带searchterm参数 - 父组件通过
@doEmitSearch="doTriggerSearch"接收事件,在<script lang="ts" setup>中导入并调用doPerformSearch组合式函数 doPerformSearch.ts包含Search1(value)、Search2(value)等函数,负责调用不同API、清洗数据,最终返回JSON格式结果
问题1:父组件如何显示doPerformSearch的返回结果?
核心是用响应式变量存储结果,确保模板能实时更新:
- 在父组件的
setup中定义响应式变量并处理异步逻辑:
<script lang="ts" setup> import { ref } from 'vue'; import doPerformSearch from './doPerformSearch'; // 定义响应式变量存储搜索结果 const searchResults = ref<any[]>([]); // 接收子组件事件的处理函数 const doTriggerSearch = async (searchterm: string) => { // API调用为异步操作,必须用async/await处理 const results = await doPerformSearch(searchterm); // 将结果赋值给响应式变量,触发模板更新 searchResults.value = results; }; </script>
- 在父组件模板中直接绑定展示:
<template> <SearchInput @doEmitSearch="doTriggerSearch" /> <!-- 直接渲染响应式结果 --> <div class="search-result">{{ searchResults }}</div> </template>
注意:如果
doPerformSearch未封装为异步函数,要先修改它返回Promise,否则无法获取API返回的真实结果。
问题2:如何将多个搜索结果传递给子组件展示?
分为父组件聚合结果和子组件接收渲染两个步骤:
父组件端:聚合多接口结果
<script lang="ts" setup> import { reactive } from 'vue'; import { Search1, Search2 } from './doPerformSearch'; // 用reactive存储多组结果,结构更清晰 const multipleResults = reactive({ search1: [], search2: [] }); const doTriggerSearch = async (searchterm: string) => { // 并行调用多个搜索接口提升效率 const [res1, res2] = await Promise.all([ Search1(searchterm), Search2(searchterm) ]); // 更新响应式数据 multipleResults.search1 = res1; multipleResults.search2 = res2; }; </script>
子组件端:通过Props接收并展示
<script lang="ts" setup> // 定义Props类型约束 defineProps<{ multipleResults: { search1: any[]; search2: any[]; }; }>(); </script> <template> <div class="multi-results"> <section class="result-group"> <h3>搜索结果组1</h3> <ul> <li v-for="item in multipleResults.search1" :key="item.id">{{ item.content }}</li> </ul> </section> <section class="result-group"> <h3>搜索结果组2</h3> <ul> <li v-for="item in multipleResults.search2" :key="item.id">{{ item.title }}</li> </ul> </section> </div> </template>
父组件传递Props:
<template> <SearchInput @doEmitSearch="doTriggerSearch" /> <!-- 驼峰命名的Props在模板中转为短横线 --> <MultiResultView :multiple-results="multipleResults" /> </template>
问题3:当前设计模式是否合理?有无更优方案?
当前模式的合理性
你的设计符合Vue3的最佳实践:
- 子组件专注UI交互(输入、事件触发),职责单一,复用性强
- 组合式函数封装API调用和数据处理,业务逻辑与组件解耦,便于复用和测试
- 父组件作为中间层协调子组件与业务逻辑,降低模块间耦合
优化方案
封装搜索状态到组合式函数
将加载、错误状态也整合到doPerformSearch中,减少父组件的状态管理代码:// doPerformSearch.ts import { ref } from 'vue'; export function useSearch() { const results = ref<any[]>([]); const loading = ref(false); const error = ref<string | null>(null); const performSearch = async (searchterm: string) => { loading.value = true; error.value = null; try { const res1 = await Search1(searchterm); const res2 = await Search2(searchterm); results.value = [...res1, ...res2]; // 按需聚合结果 } catch (err) { error.value = (err as Error).message; } finally { loading.value = false; } }; return { results, loading, error, performSearch }; }父组件使用时只需调用函数并解构状态:
import { useSearch } from './doPerformSearch'; const { results, loading, error, performSearch } = useSearch(); const doTriggerSearch = (searchterm: string) => performSearch(searchterm);添加搜索防抖
避免输入时频繁触发API调用,可在子组件中添加防抖处理:// 子组件中实现防抖 import { debounce } from 'lodash-es'; const emit = defineEmits<{ doEmitSearch: [searchterm: string]; }>(); // 300ms内连续输入只触发一次事件 const debouncedEmit = debounce((term: string) => { emit('doEmitSearch', term); }, 300); const handleInput = (e: Event) => { const term = (e.target as HTMLInputElement).value; debouncedEmit(term); };子组件直接使用组合式函数(可选)
如果项目规模较小、业务逻辑简单,可让子组件直接调用useSearch,减少父组件的中间协调,但会增加子组件与业务逻辑的耦合,需根据场景权衡。
内容的提问来源于stack exchange,提问作者SimbaNinja
相关产品推荐
相关产品推荐

