Vue3 Todo应用:如何将父组件元素推送到子组件的todos数组?
Todo应用跨组件添加任务的两种简单实现方案
方案一:组件引用调用内部方法(最小改动)
这种方式无需调整现有组件核心逻辑,仅给List组件添加暴露方法,让App.vue通过组件引用调用即可。
- 修改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>
- 修改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单向数据流原则,组件职责更清晰。
- 修改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>
- 修改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
相关产品推荐
相关产品推荐

