Vue2 组件间复杂数据传递:父子、兄弟、跨层级通信全解析

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 实现跨层级通信

完整代码已提供,快来试试吧!🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈探索者chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值