方向对,但"解绑责任收进 composable"有个前提:每次调用得拿到独立的 handler 引用,否则 off 会互相抵消。
composable 里如果 handler 是组件外部定义的具名函数(模块级常量),两个组件同时订阅同一事件,先卸载的那个 off(name, handler) 会把后者的订阅一起摘掉——所以 handler 要在 composable 函数体内新建闭包,或者由调用方传进来、由调用方负责 off。返回 dispose 函数也是个好习惯,兼容非 setup 环境(在 setTimeout、事件回调里调 composable 时 onUnmounted 根本注册不上)。
bus.all.clear() 我建议只在「bus 不是全局单例」时用。更根本的解法是让 bus 的作用域跟着模块或页面走——每个页面/模块 createBus() 一个实例,卸载时 all.clear() 只清自己那块,零误伤;全局单例 + clear 在 keep-alive、全局通知、多标签页这类场景会连还在用的订阅一起干掉,非常难排查。
如果非要保留全局单例,粒度上还有中间档:bus.off(type) 不传 handler 会清掉该事件的全部订阅,比 all.clear() 精准一层,清理某个功能域的订阅用它更安全。
坑就一个:all.clear() 清不掉"事后又 on 上来"的订阅,如果组件卸载后有异步任务补注册,得靠 dispose 标志位拦一道。
见习用户






