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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 15:45:49