Vue.js如何在三个无父子关联的组件间传值实现待办项添加功能?
解决方案
不需要引入Vuex,也不需要合并组件,使用Vue内置的跨组件通信方案即可实现需求,以下是Vue2和Vue3两个版本的实现方式:
Vue2 实现方案(用事件总线)
事件总线是Vue2原生支持的轻量级跨组件通信方式,无需引入额外依赖。
步骤1:全局注册事件总线
在项目入口文件main.js中添加如下代码:
import Vue from 'vue' // 新增这一行,挂载全局事件总线 Vue.prototype.$bus = new Vue() // 原有其他代码... new Vue({ render: h => h(App) }).$mount('#app')
步骤2:修正各组件代码
1. 表单组件 TodoTemplate
修正错误的props写法,移除重复的value绑定,监听添加按钮的提交事件,触发时传递当前填写的待办数据:
<template> <div ref="template" class="task-template"> <div class="task-template__wrapper"> <div class="task-template__input"> <input v-model="todo.header" ref="header" class="task-template__header" type="text" placeholder="Название задачи"> </div> <div class="task-template__input"> <input v-model="todo.description" ref="description" class="task-template__description" type="text" placeholder="Описание"> </div> </div> <div class="task-template__actions"> <div class="task-template__actions_inner"> <inline-svg class="task-template__btn hover" alt="Подзадачи" :src="getImageUrl(`bulleted-list.svg`)"></inline-svg> <inline-svg class="task-template__btn" alt="Добавить в группу" :src="getImageUrl(`folder.svg`)"></inline-svg> </div> </div> </div> </template> <script> export default { name: "TodoTemplate", props: { initTodo: { type: Object, // 对象类型默认值必须用工厂函数返回 default: () => ({ header: "", description: "", tasks: [], groups: [] }) } }, data() { return { todo: {...this.initTodo} } }, created() { // 监听添加按钮的提交事件 this.$bus.$on('trigger-submit-todo', () => { // 把当前填写的待办数据传给列表组件 this.$bus.$emit('submit-todo', this.todo) // 提交后清空表单 this.todo = {header: '', description: '', tasks: [], groups: []} }) }, beforeDestroy() { // 组件销毁前移除事件监听,避免内存泄漏 this.$bus.$off('trigger-submit-todo') } } </script>
2. 添加按钮组件 CreateTodo
修正this指向错误,点击时发射提交触发事件:
<template> <div class="add-button" @click="submit"> <div class="add-button__container"> Добавить задачу </div> </div> </template> <script> export default { name: "CreateTodo", methods: { // 不要用箭头函数,否则this指向不对 submit() { this.$bus.$emit("trigger-submit-todo") } } } </script>
3. 待办列表组件 TodoList
监听待办提交事件,调用新增方法,修正v-for的key值错误:
<template> <section> <!-- 给表单组件绑定初始空todo --> <TodoTemplate :init-todo="newTodo" /> <ul class="todo"> <TodoItem v-for="todo in todos" :title="todo.header" :key="todo.header" /> </ul> </section> </template> <script> import TodoTemplate from "@/components/TodoTemplate/TodoTemplate"; import TodoItem from "@/components/TodoItem/TodoItem"; export default { name: "TodoList", components: {TodoItem, TodoTemplate}, data() { return { newTodo: { header: "", description: "", tasks: [], groups: [] }, todos: [ { header: '🍾 Купить шампанское', description: '"Dom Perignon", Rose Vintage 2003 Brut', tasks: [], groups: [] } ] } }, created() { // 监听表单提交的待办数据 this.$bus.$on('submit-todo', (todo) => { this.addTodo(todo) }) }, beforeDestroy() { this.$bus.$off('submit-todo') }, methods: { addTodo(todo) { // 深拷贝避免引用问题 this.todos.push(JSON.parse(JSON.stringify(todo))) } } } </script>
Vue3 实现方案(用 provide/inject)
Vue3移除了事件总线,无需引入mitt的情况下可以用原生的provide/inject实现全局状态共享,在根组件App.vue提供共享的待办列表和新增方法,所有组件都可以注入调用。
内容的提问来源于stack exchange,提问作者sashafromlibertalia
相关产品推荐
相关产品推荐

