Vue中能否通过this.$refs监听子组件自定义事件?
能否通过
this.$refs监听子组件自定义事件? 答案需分Vue 2和Vue 3两种场景说明:
Vue 2 可行
在Vue 2中,组件实例继承了事件订阅相关方法($on、$off、$once),因此可以通过this.$refs获取子组件实例后,直接用$on监听自定义事件:
修改后的父组件示例
<template> <child-component ref="myChild" /> </template> <script> export default { mounted () { // 监听子组件的iterated事件 this.$refs.myChild.$on('iterated', (count) => { console.log(count); }); }, beforeUnmount() { // 组件销毁前移除监听,避免内存泄漏 this.$refs.myChild.$off('iterated'); } }; </script>
如果只需要监听一次事件,可使用$once替代$on,无需手动移除监听。
Vue 3 不可行(需用替代方案)
Vue 3彻底移除了组件实例上的$on、$off、$once方法,直接调用this.$refs.myChild.on()或$on()会报错。以下是几种可行的替代方案:
方案1:子组件暴露事件订阅方法
在子组件中手动实现事件订阅逻辑,允许父组件通过refs注册回调:
子组件修改
<template> <p>Count: {{ count }} </p> </template> <script> export default { data: () => ({ count: 1, iteratedCallbacks: [] }), methods: { onIterated(callback) { this.iteratedCallbacks.push(callback); }, offIterated(callback) { this.iteratedCallbacks = this.iteratedCallbacks.filter(cb => cb !== callback); } }, mounted () { setTimeout(() => { this.count++; // 触发所有注册的回调 this.iteratedCallbacks.forEach(cb => cb(this.count)); }, 2000); } }; </script>
父组件调用
<template> <child-component ref="myChild" /> </template> <script> export default { mounted () { const handleIterated = (count) => { console.log(count); }; this.$refs.myChild.onIterated(handleIterated); // 组件销毁时移除回调 this.$once('hook:beforeUnmount', () => { this.$refs.myChild.offIterated(handleIterated); }); } }; </script>
方案2:将回调作为Props传入父组件
如果事件触发时机可预测,可以直接把回调函数作为Props传给子组件:
子组件修改
<template> <p>Count: {{ count }} </p> </template> <script> export default { props: { onIterated: { type: Function, default: () => {} } }, data: () => ({ count: 1 }), mounted () { setTimeout(() => { this.count++; this.onIterated(this.count); }, 2000); } }; </script>
父组件使用
<template> <child-component :on-iterated="handleIterated" /> </template> <script> export default { methods: { handleIterated(count) { console.log(count); } } }; </script>
方案3:使用第三方事件总线库(如mitt)
通过mitt创建全局或局部事件总线,子组件触发事件,父组件监听事件:
- 安装mitt:
npm install mitt - 创建事件总线实例:
// eventBus.js import mitt from 'mitt'; export const emitter = mitt();
子组件修改
<template> <p>Count: {{ count }} </p> </template> <script> import { emitter } from './eventBus'; export default { data: () => ({ count: 1 }), mounted () { setTimeout(() => { this.count++; emitter.emit('iterated', this.count); }, 2000); } }; </script>
父组件监听
<template> <child-component ref="myChild" /> </template> <script> import { emitter } from './eventBus'; export default { mounted () { emitter.on('iterated', (count) => { console.log(count); }); }, beforeUnmount() { emitter.off('iterated'); } }; </script>
内容的提问来源于stack exchange,提问作者pixelmusik
相关产品推荐
相关产品推荐

