大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript
等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter
等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js
进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。
技术qq交流群:906392632
大家好,我是小杨,一个摸爬滚打了6年的前端老司机。今天咱们聊聊Vue组件通信这个老生常谈但又极其重要的话题。为啥说它重要呢?因为在实际项目中,组件之间不会说话可不行啊!想象一下,你和同事在一个办公室却没法交流,那工作还怎么开展?
一、Props:父子组件间的"正经"对话
Props是Vue中最基础的父子组件通信方式,就像父亲给儿子零花钱一样直接。
javascript
// 父组件
<template>
<ChildComponent :allowance="100" :message="'我给你的零花钱'" />
</template>
// 子组件
export default {
props: {
allowance: Number,
message: String
},
mounted() {
console.log(`${this.message}: ${this.allowance}元`)
// 输出: 我给你的零花钱: 100元
}
}
注意点:
- Props是单向数据流,父级prop的更新会向下流动到子组件
- 不要直接在子组件修改prop,Vue会发出警告
- 可以用计算属性或者data中的本地变量来接收prop的初始值
二、$emit:儿子有话要对爸爸说
当子组件需要向父组件传递数据时,$emit就派上用场了。
javascript
// 子组件
<button @click="askForMore">再给点零花钱</button>
methods: {
askForMore() {
this.$emit('increase-allowance', {
amount: 50,
reason: '我最近学习很用功'
})
}
}
// 父组件
<ChildComponent @increase-allowance="handleIncrease" />
methods: {
handleIncrease(payload) {
console.log(`理由: ${payload.reason}, 要求增加: ${payload.amount}元`)
// 输出: 理由: 我最近学习很用功, 要求增加: 50元
}
}
实用技巧:
- 自定义事件名推荐使用kebab-case(短横线分隔)
- 可以传递多个参数,但更推荐使用对象形式
- .native修饰符可以监听原生事件(Vue 2)
三、$refs:直接呼叫组件实例
有时候我们需要直接访问子组件的方法或数据,这时候$refs就很有用了。
javascript
// 父组件
<ChildComponent ref="child" />
methods: {
callChildMethod() {
this.$refs.child.doSomething('我直接调用你的方法啦!')
}
}
// 子组件
methods: {
doSomething(message) {
console.log(message) // 输出: 我直接调用你的方法啦!
}
}
注意事项:
- $refs只在组件渲染完成后才填充
- 不是响应式的,避免在模板或计算属性中使用
- 过度使用$refs可能破坏组件封装性
四、EventBus:组件间的"对讲机"
对于非父子关系的组件,EventBus提供了一个中央事件系统。
javascript
// eventBus.js
import Vue from 'vue'
export const EventBus = new Vue()
// 组件A (发送事件)
import { EventBus } from './eventBus'
EventBus.$emit('message', '我发了一条广播消息')
// 组件B (接收事件)
import { EventBus } from './eventBus'
EventBus.$on('message', (message) => {
console.log(message) // 输出: 我发了一条广播消息
})
最佳实践:
- 记得在组件销毁时移除事件监听,避免内存泄漏
- 对于大型项目,建议使用Vuex替代EventBus
- 事件名可以用常量管理,避免拼写错误
五、provide/inject:祖孙组件"隔代遗传"
这对API允许祖先组件向其所有子孙后代注入依赖。
javascript
// 祖先组件
export default {
provide() {
return {
familyName: '杨家',
sayHello: () => console.log('我是你爷爷')
}
}
}
// 后代组件
export default {
inject: ['familyName', 'sayHello'],
mounted() {
console.log(`我属于${this.familyName}`) // 输出: 我属于杨家
this.sayHello() // 输出: 我是你爷爷
}
}
使用场景:
- 适合开发高阶插件/组件库
- 不推荐在普通应用代码中使用,因为会使组件间关系变得不透明
- 注入的数据不是响应式的(除非传入一个响应式对象)
六、Vuex:全局状态"大管家"
对于复杂应用,Vuex提供了集中式状态管理。
javascript
// store.js
export default new Vuex.Store({
state: {
wallet: 1000
},
mutations: {
SPEND_MONEY(state, payload) {
state.wallet -= payload.amount
console.log(`我花了${payload.amount}元,还剩${state.wallet}元`)
}
}
})
// 组件中使用
methods: {
buySomething() {
this.$store.commit('SPEND_MONEY', {
amount: 100,
item: '新键盘'
})
// 输出: 我花了100元,还剩900元
}
}
Vuex使用心得:
- 不要直接修改state,一定要通过mutations
- 对于异步操作使用actions
- 大型项目可以分模块管理
- 考虑使用mapState、mapGetters等辅助函数简化代码
七、其他通信方式
- <math xmlns="http://www.w3.org/1998/Math/MathML"> a t t r s / attrs/ </math>attrs/listeners:跨级组件通信的好帮手
- <math xmlns="http://www.w3.org/1998/Math/MathML"> p a r e n t / parent/ </math>parent/children:直接访问父/子实例(慎用)
- 浏览器存储:localStorage/sessionStorage
- 路由参数:通过路由传递数据
总结
这么多通信方式,怎么选呢?我的经验是:
- 父子组件:优先用props/$emit
- 兄弟组件:用共同的父组件中转或EventBus
- 跨多级组件:考虑provide/inject或Vuex
- 全局状态:用Vuex
记住,没有最好的通信方式,只有最合适的。就像我当年刚学Vue时,总喜欢用EventBus解决一切问题,结果项目大了事件满天飞,维护起来要命。后来合理使用Vuex,代码才清爽起来。