Vue2 组件间复杂数据传递:父子、兄弟、跨层级通信全解析
在 Vue2 项目中,组件间通信是开发中不可避免的问题。随着业务复杂度增加,如何 高效地管理组件间的数据流,成为了提升应用可维护性和可扩展性的关键。
本篇文章从 父子、兄弟、跨层级组件通信 角度,结合 完整的实战案例(TodoList 应用),深入解析 Vue2 组件间数据传递的方法。
1. Vue2 组件间通信方式
在 Vue2 中,常见的组件通信方式如下:
通信方式 | 适用场景 | 方法 |
---|---|---|
Props + Emit | 父组件 → 子组件,子组件通知父组件 | props 传值,$emit 事件通知父组件 |
v-model/sync | 父子组件双向绑定 | v-model 绑定 value ,子组件 $emit('input', 新值) |
$attrs & $listeners | 透传 props 和 事件 | 解决多级嵌套组件的 props 传递 |
EventBus | 兄弟组件 | 事件总线 $emit / $on 监听事件 |
Vuex | 全局状态管理 | 共享数据 state ,修改数据 mutations |
Provide/Inject | 跨层级组件 | 祖先组件 provide 数据,子孙组件 inject |
2. 实战案例:构建 TodoList 应用
功能需求
✅ 父组件 App.vue
:管理任务列表,可添加/删除任务。
✅ 子组件 TaskItem.vue
:显示任务项,支持状态切换。
✅ 兄弟组件 TaskFilter.vue
:筛选任务(全部、已完成、未完成)。
✅ 跨层级组件 TaskSummary.vue
:统计任务数量(Provide/Inject
)。
✅ 使用 EventBus 处理兄弟组件通信。
✅ 使用 Vuex 进行全局状态管理。
3. 搭建 Vue2 项目
安装 Vue2 项目
vue create vue2-todo
cd vue2-todo
npm install vuex
项目结构
vue2-todo
│── src
│ ├── components
│ │ ├── TaskItem.vue # 任务项组件
│ │ ├── TaskFilter.vue # 任务筛选组件
│ │ ├── TaskSummary.vue # 任务统计组件
│ ├── store
│ │ ├── index.js # Vuex 状态管理
│ ├── App.vue # 父组件
│ ├── main.js # 入口文件
│── package.json
│── index.html
4. Vuex 任务状态管理
在 store/index.js
里创建任务全局状态:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
tasks: [],
filter: 'all' // 可选值:all, completed, pending
},
mutations: {
ADD_TASK(state, text) {
state.tasks.push({ id: Date.now(), text, completed: false });
},
REMOVE_TASK(state, id) {
state.tasks = state.tasks.filter(task => task.id !== id);
},
TOGGLE_TASK(state, id) {
const task = state.tasks.find(task => task.id === id);
if (task) task.completed = !task.completed;
},
SET_FILTER(state, filter) {
state.filter = filter;
}
},
getters: {
filteredTasks: (state) => {
if (state.filter === 'completed') return state.tasks.filter(task => task.completed);
if (state.filter === 'pending') return state.tasks.filter(task => !task.completed);
return state.tasks;
},
completedCount: state => state.tasks.filter(task => task.completed).length,
totalCount: state => state.tasks.length
}
});
5. 事件总线(EventBus 处理兄弟组件通信)
在 src/eventBus.js
创建事件总线:
import Vue from 'vue';
export const eventBus = new Vue();
6. 组件开发
6.1 TaskItem.vue
(子组件,接收 props
,触发 $emit
事件)
<template>
<li>
<input type="checkbox" :checked="task.completed" @change="$emit('toggle', task.id)" />
<span :class="{ completed: task.completed }">{{ task.text }}</span>
<button @click="$emit('remove', task.id)">删除</button>
</li>
</template>
<script>
export default {
props: ['task']
};
</script>
<style scoped>
.completed {
text-decoration: line-through;
}
</style>
6.2 TaskFilter.vue
(兄弟组件,使用 EventBus)
<template>
<div>
<button @click="setFilter('all')">全部</button>
<button @click="setFilter('completed')">已完成</button>
<button @click="setFilter('pending')">未完成</button>
</div>
</template>
<script>
import { eventBus } from '../eventBus';
export default {
methods: {
setFilter(filter) {
eventBus.$emit('filterChanged', filter);
}
}
};
</script>
6.3 TaskSummary.vue
(跨层级组件,使用 Provide/Inject)
<template>
<div>
<p>已完成任务:{{ completedCount }} / {{ totalCount }}</p>
</div>
</template>
<script>
export default {
inject: ['completedCount', 'totalCount']
};
</script>
6.4 App.vue
(父组件,整合所有功能)
<template>
<div>
<h1>Vue2 复杂组件通信</h1>
<input v-model="newTask" placeholder="输入任务..." />
<button @click="addTask">添加任务</button>
<TaskFilter />
<ul>
<TaskItem
v-for="task in filteredTasks"
:key="task.id"
:task="task"
@remove="removeTask"
@toggle="toggleTask"
/>
</ul>
<TaskSummary />
</div>
</template>
<script>
import { mapState, mapMutations, mapGetters } from 'vuex';
import { eventBus } from './eventBus';
import TaskItem from './components/TaskItem.vue';
import TaskFilter from './components/TaskFilter.vue';
import TaskSummary from './components/TaskSummary.vue';
export default {
components: { TaskItem, TaskFilter, TaskSummary },
data() {
return { newTask: '' };
},
computed: {
...mapGetters(['filteredTasks'])
},
methods: {
...mapMutations(['ADD_TASK', 'REMOVE_TASK', 'TOGGLE_TASK']),
addTask() {
if (this.newTask.trim()) {
this.ADD_TASK(this.newTask);
this.newTask = '';
}
}
},
created() {
eventBus.$on('filterChanged', filter => {
this.$store.commit('SET_FILTER', filter);
});
},
provide() {
return {
completedCount: this.$store.getters.completedCount,
totalCount: this.$store.getters.totalCount
};
}
};
</script>
7. 总结
✅ Props/Emit 实现父子通信
✅ EventBus 处理兄弟组件交互
✅ Vuex 全局状态管理
✅ Provide/Inject 实现跨层级通信
完整代码已提供,快来试试吧!🚀