自定义事件是 vue 中实现观察者模式最自然的方式,子组件通过 $emit 发布事件,父组件用 v-on 订阅,双方无直接引用、松耦合;跨层级可用 eventbus,需手动清理监听器。

自定义事件是 Vue 中实现观察者模式最自然的方式,它让父子组件之间不直接调用、不互相持有引用,只通过“事件发布-订阅”建立松散联系。核心在于:子组件是事件发布者(Subject),父组件是观察者(Observer),中间没有硬依赖。
子组件触发事件:用 $emit 发布状态变化
子组件不关心谁监听,只负责在合适时机调用 $emit 发出事件和数据。比如按钮点击后通知父组件更新状态:
- 事件名建议语义化,如 'update-user'、'item-removed',避免用 'click' 这类原生名造成歧义
- 可传多个参数,但推荐只传一个对象,便于后续扩展:
this.$emit('user-updated', { id: 123, name: 'Alice' }) - 不要在子组件里写
this.$parent.xxx()—— 这会重新引入强耦合,违背观察者初衷
父组件监听事件:用 v-on 声明式订阅
父组件在使用子组件标签时,用 v-on(或 @)绑定处理函数。它只声明“我关心这个事件”,不主动拉取、不轮询、不持有子组件实例:
- 写法简洁:
<user-form></user-form> - 处理函数接收子组件传来的参数,执行本地逻辑,比如更新列表、弹提示、跳转路由
- 无需手动解绑 —— Vue 在组件卸载时自动清理 v-on 绑定的事件监听器
进阶:跨层级或动态通信可用事件总线(EventBus)
当父子嵌套较深,或需要临时让非直系组件通信时,可创建一个空 Vue 实例作为中央事件总线。它本质是观察者模式的集中式 Subject:
- 定义:
const bus = new Vue()(Vue 2)或用 mitt / tiny-emitter(Vue 3) - 子组件发:
bus.$emit('data-ready', payload) - 父组件(或其他任意组件)收:
bus.$on('data-ready', handler),记得在beforeDestroy或onUnmounted中$off避免内存泄漏 - 适合一次性通知、全局状态广播等场景,但不宜替代常规父子通信
为什么这算真正的观察者模式?
它完全符合观察者模式四要素:
-
Subject(主题):子组件,维护自身状态,提供
$emit接口发布变更 - Observer(观察者):父组件,实现响应逻辑(即事件处理器),不主动查询子组件
- 松耦合:子组件不知道父组件存在;父组件可随时更换处理逻辑,不影响子组件
- 一对多支持:同一事件可被多个父级或兄弟组件监听,无需修改子组件代码










