Vue3组件间函数调用实现:ItemForm提交触发ItemsList添加列表项
Vue3 兄弟组件通信解决方案(替代EventBus)
对于你的列表添项应用,最规范的做法是将共享状态提升到共同父组件(App.vue),通过父组件作为中间层实现ItemForm和ItemsList的数据传递,完全符合Vue3的单向数据流原则,替代Vue2的EventBus方案。
以下是具体修改步骤:
1. 修改App.vue:托管共享状态
把列表数据和添加逻辑移到父组件,分别传递给两个子组件:
<template> <div> <ItemsList :items="items" /> </div> <div> <ItemForm @add-item="handleAddItem" /> </div> </template> <script setup> import { ref } from 'vue' import ItemForm from "@/components/ItemForm"; import ItemsList from "@/components/ItemsList"; // 共享的列表数据 const items = ref([]) // 处理添加项的方法 const handleAddItem = (newItem) => { items.value.push(newItem) } </script>
2. 修改ItemForm.vue:触发自定义事件传递数据
表单提交时,触发自定义事件把数据传给父组件,同时清空表单:
<template> <form @submit="handleSubmit"> <input type="text" v-model="title" placeholder="输入标题"/> <textarea v-model="description" placeholder="输入描述"></textarea> <button>Add item</button> </form> </template> <script setup> import { ref } from 'vue' const title = ref('') const description = ref('') // 声明要触发的事件 defineEmits(['add-item']) const handleSubmit = (e) => { e.preventDefault() // 简单校验空输入 if (!title.value.trim()) return // 触发事件传递新项数据 emit('add-item', { title: title.value, description: description.value }) // 清空表单 title.value = '' description.value = '' } </script>
如果习惯用选项式API,修改如下:
<template> <form @submit="handleSubmit"> <input type="text" v-model="title" placeholder="输入标题"/> <textarea v-model="description" placeholder="输入描述"></textarea> <button>Add item</button> </form> </template> <script> export default { data() { return { title: '', description: '' } }, emits: ['add-item'], methods: { handleSubmit(e) { e.preventDefault(); if (!this.title.trim()) return this.$emit('add-item', { title: this.title, description: this.description }) this.title = '' this.description = '' } } } </script>
3. 修改ItemsList.vue:通过Props接收数据
不再自己维护items数组,改为接收父组件传递的props:
<template> <ul> <li v-for="(item, index) in items" :key="index"> <p><b>{{ item.title }}</b></p> <p>{{ item.description }}</p> </li> </ul> </template> <script setup> // 定义props规则 defineProps({ items: { type: Array, required: true, default: () => [] } }) </script>
选项式API版本:
<template> <ul> <li v-for="(item, index) in items" :key="index"> <p><b>{{ item.title }}</b></p> <p>{{ item.description }}</p> </li> </ul> </template> <script> export default { props: { items: { type: Array, required: true, default: () => [] } } } </script>
方案优势
- 遵循Vue单向数据流原则,数据流向清晰,避免EventBus带来的全局事件混乱问题
- 代码结构更易维护,后续如果应用复杂度提升,可以无缝迁移到Pinia状态管理库
- 子组件职责单一:ItemForm负责收集用户输入,ItemsList负责展示数据,父组件负责状态管理
内容的提问来源于stack exchange,提问作者Zaki
相关产品推荐
相关产品推荐

