盘点Vue2 组件通信方式

408 阅读2分钟

Vue2 组件通信全解析

在 Vue2 中,组件之间的通信是构建复杂应用的关键。本文将详细介绍 Vue2 中各种组件通信方式,包括父子组件通信、任意组件通信等,并提供代码示例。

1. 父组件向子组件传值:props

props 是 Vue 中最基础的父子组件通信方式,父组件通过 props 向子组件传递数据。

html
	<!-- 父组件 Parent.vue -->
	<template>
	  <div>
	    <h2>父组件</h2>
	    <Child :message="parentMessage" :userInfo="userData" />
	  </div>
	</template>

	<script>
	import Child from './Child.vue'

	export default {
	  components: { Child },
	  data() {
	    return {
	      parentMessage: 'Hello from Parent',
	      userData: {
	        name: 'John',
	        age: 30
	      }
	    }
	  }
	}
	</script>
html
	<!-- 子组件 Child.vue -->
	<template>
	  <div>
	    <h3>子组件</h3>
	    <p>父组件消息: {{ message }}</p>
	    <p>用户信息: {{ userInfo.name }} - {{ userInfo.age }}</p>
	  </div>
	</template>

	<script>
	export default {
	  props: {
	    message: {
	      type: String,
	      required: true
	    },
	    userInfo: {
	      type: Object,
	      default: () => ({})
	    }
	  }
	}
	</script>

2. 子组件向父组件传值

方式一:使用自定义事件

html
	<!-- 父组件 Parent.vue -->
	<template>
	  <div>
	    <h2>父组件</h2>
	    <Child @send-data="handleData" />
	    <p>来自子组件的数据: {{ childData }}</p>
	  </div>
	</template>
	<script>
	import Child from './Child.vue'

	export default {
	  components: { Child },
	  data() {
	    return {
	      childData: ''
	    }
	  },
	  methods: {
	    handleData(data) {
	      this.childData = data
	    }
	  }
	}

	</script>
html
	<!-- 子组件 Child.vue -->
	<template>
	  <div>
	    <h3>子组件</h3>
	    <button @click="sendDataToParent">发送数据给父组件</button>
	  </div>
	</template>
	<script>
	export default {
	  methods: {
	    sendDataToParent() {
	      this.$emit('send-data', 'Data from Child')
	    }
	  }
	}
	</script>

方式二:使用 ref

html
	<!-- 父组件 Parent.vue -->

	<template>
	  <div>
	    <h2>父组件</h2>
	    <Child ref="childRef" />
	    <p>来自子组件的数据: {{ childData }}</p>
	  </div>
	</template>

	<script>
	import Child from './Child.vue'

	export default {
	  components: { Child },
	  data() {
	    return {
	      childData: ''
	    }
	  },
	  mounted() {
	    this.$refs.childRef.$on('custom-event', (data) => {
	      this.childData = data
	    })
	  },
	  beforeDestroy() {
	    // 避免内存泄漏
	    this.$refs.childRef.$off('custom-event')
	  }
	}
	</script>
html
	<!-- 子组件 Child.vue -->
	<template>
	  <div>
	    <h3>子组件</h3>
	    <button @click="triggerCustomEvent">触发自定义事件</button>
	  </div>
	</template>

	<script>
	export default {
	  methods: {
	    triggerCustomEvent() {
	      this.$emit('custom-event', 'Custom event data')
	    }

	  }

	}

	</script>

3. 任意组件间通信

方式一:Vuex 状态管理

首先安装 Vuex:

bash
	npm install vuex
js
	// store.js

	import Vue from 'vue'
	import Vuex from 'vuex'

	Vue.use(Vuex)

	export default new Vuex.Store({
	  state: {
	    sharedData: 'Initial data from Vuex'
	  },

	  mutations: {
	    updateSharedData(state, payload) {
	      state.sharedData = payload
	    }
	  },
	  actions: {
	    updateData({ commit }, data) {
	      commit('updateSharedData', data)
	    }
	  },
	  getters: {
	    getSharedData: state => state.sharedData
	  }
	})
html
	<!-- 组件A ComponentA.vue -->

	<template>
	  <div>
	    <h3>组件A</h3>
	    <p>共享数据: {{ sharedData }}</p>
	    <button @click="updateData">更新数据</button>
	  </div>
	</template>
	<script>
	import { mapGetters, mapActions } from 'vuex'

	export default {
	  computed: {
	    ...mapGetters(['getSharedData']),
	    sharedData() {
	      return this.getSharedData
	    }
	  },
	  methods: {
	    ...mapActions(['updateData']),
	    updateData() {
	      this.updateData('Updated from Component A')
	    }
	  }
	}
	</script>
html
	<!-- 组件B ComponentB.vue -->

	<template>
	  <div>
	    <h3>组件B</h3>
	    <p>共享数据: {{ sharedData }}</p>
	  </div>
	</template>

	<script>

	import { mapGetters } from 'vuex'

	export default {
	  computed: {
	    ...mapGetters(['getSharedData']),
	    sharedData() {
	      return this.getSharedData
	    }
	  }
	}
	</script>

方式二:全局事件总线

js
	// main.js
	import Vue from 'vue'
	import App from './App.vue'

	// 创建事件总线
	Vue.prototype.$eventBus = new Vue()

	new Vue({
	  render: h => h(App)
	}).$mount('#app')
html
	<!-- 发送组件 Sender.vue -->
	<template>
	  <div>
	    <h3>发送组件</h3>
	    <button @click="sendMessage">发送全局消息</button>
	  </div>
	</template>

	<script>
	export default {
	  methods: {
	    sendMessage() {
	      this.$eventBus.$emit('global-event', 'Message from Sender')
	    }
	  }
	}
	</script>
html
	<!-- 接收组件 Receiver.vue -->

	<template>
	  <div>
	    <h3>接收组件</h3>
	    <p>全局消息: {{ globalMessage }}</p>
	  </div>
	</template>

	<script>
	export default {
	  data() {
	    return {
	      globalMessage: ''
	    }
	  },
	  mounted() {
	    this.$eventBus.$on('global-event', (msg) => {
	      this.globalMessage = msg
	    })
	  },
	  beforeDestroy() {
	    // 避免内存泄漏
	    this.$eventBus.$off('global-event')
	  }
	}
	</script>

总结

  1. 父子组件通信

    • 父传子:使用 props
    • 子传父:使用自定义事件($emit)或 ref
  2. 任意组件通信

    • Vuex:适合大型应用,集中管理状态
    • 全局事件总线:适合小型应用,简单直接
  3. 最佳实践

    • 简单父子通信使用 props 和 $emit
    • 复杂应用或兄弟组件通信使用 Vuex
    • 小型项目可以考虑事件总线,但要注意及时销毁事件监听避免内存泄漏

选择哪种通信方式取决于应用规模和组件关系的复杂度。对于简单应用,props 和自定义事件通常足够;对于大型应用,Vuex 提供了更可预测的状态管理。