You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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创建全局或局部事件总线,子组件触发事件,父组件监听事件:

  1. 安装mitt:npm install mitt
  2. 创建事件总线实例:
// 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 04:30:41