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

Vue3 Todo应用:如何将父组件元素推送到子组件的todos数组?

Todo应用跨组件添加任务的两种简单实现方案

方案一:组件引用调用内部方法(最小改动)

这种方式无需调整现有组件核心逻辑,仅给List组件添加暴露方法,让App.vue通过组件引用调用即可。

  1. 修改List组件,新增添加任务的方法并暴露给父组件:
<script setup>
import { ref } from 'vue'

// 原有todos数组与操作逻辑
const todos = ref([
  // 初始任务数据
])

const toggleTodo = (id) => {
  const todo = todos.value.find(t => t.id === id)
  if (todo) todo.completed = !todo.completed
}

const deleteTodo = (id) => {
  todos.value = todos.value.filter(t => t.id !== id)
}

// 新增:添加任务的方法
const addTodoItem = (newTodo) => {
  todos.value.push(newTodo)
}

// 暴露方法供父组件调用
defineExpose({ addTodoItem })
</script>
  1. 修改App.vue,给List组件添加ref引用,在addTodo方法中调用List的暴露方法:
<script setup>
import { ref } from 'vue'
import Header from './components/Header.vue'
import List from './components/List.vue'
import AddTodo from './components/AddTodo.vue'

// 定义List组件的引用
const listRef = ref(null)

const addTodo = (todoText) => {
  const newTodo = {
    id: Date.now(),
    text: todoText,
    completed: false
  }
  // 调用List组件的添加方法,可选链避免初始化时的null报错
  listRef.value?.addTodoItem(newTodo)
}
</script>

<template>
  <div class="app">
    <Header />
    <!-- 给List组件添加ref属性 -->
    <List ref="listRef" />
    <AddTodo @add-todo="addTodo" />
  </div>
</template>

方案二:状态提升(Vue推荐的数据流动方式)

将todos数组的管理权提升到App.vue容器组件,List组件通过props接收数据、通过事件触发修改,符合Vue单向数据流原则,组件职责更清晰。

  1. 修改App.vue,统一管理todos数组与所有操作方法:
<script setup>
import { ref } from 'vue'
import Header from './components/Header.vue'
import List from './components/List.vue'
import AddTodo from './components/AddTodo.vue'

const todos = ref([
  // 初始任务数据
])

// 添加任务
const addTodo = (todoText) => {
  const newTodo = {
    id: Date.now(),
    text: todoText,
    completed: false
  }
  todos.value.push(newTodo)
}

// 切换任务完成状态
const toggleTodo = (id) => {
  const todo = todos.value.find(t => t.id === id)
  if (todo) todo.completed = !todo.completed
}

// 删除任务
const deleteTodo = (id) => {
  todos.value = todos.value.filter(t => t.id !== id)
}
</script>

<template>
  <div class="app">
    <Header />
    <!-- 传递todos数据与事件监听 -->
    <List :todos="todos" @toggle-todo="toggleTodo" @delete-todo="deleteTodo" />
    <AddTodo @add-todo="addTodo" />
  </div>
</template>
  1. 修改List组件,通过props接收数据,触发事件让父组件处理修改:
<script setup>
// 定义props接收todos数据
const props = defineProps({
  todos: {
    type: Array,
    required: true
  }
})

// 定义要触发的事件
const emit = defineEmits(['toggle-todo', 'delete-todo'])

// 触发切换事件
const toggleTodo = (id) => {
  emit('toggle-todo', id)
}

// 触发删除事件
const deleteTodo = (id) => {
  emit('delete-todo', id)
}
</script>

<template>
  <ul class="todo-list">
    <li v-for="todo in todos" :key="todo.id" :class="{ completed: todo.completed }">
      <span @click="toggleTodo(todo.id)">{{ todo.text }}</span>
      <button @click="deleteTodo(todo.id)">删除</button>
    </li>
  </ul>
</template>

方案选择

  • 若想最小化修改现有代码,优先选方案一;
  • 若希望组件结构更规范、符合Vue单向数据流,优先选方案二。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 06:24:51