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

Vue3组合式API改造:render组件监听子组件事件替代$on方案

Vue3组合式API替代$on监听事件方案

针对你需要将Vue2中使用$on监听事件的代码转换为Vue3组合式API的场景,这里提供两种可行方案:

方案一:自定义简易事件发射器(无需第三方库)

由于Vue3移除了组件实例的$on/$off方法,我们可以在组件内部实现一个轻量事件发射器替代:

import { ref, h } from 'vue';

export default {
  setup(props, { slots }) {
    // 响应式变量
    const elementTop = ref(0);
    const elementHeight = ref(0);
    // 绑定组件根元素
    const rootEl = ref(null);

    // 简易事件发射器
    const eventBus = {
      events: {},
      on(eventName, handler) {
        this.events[eventName] = this.events[eventName] || [];
        this.events[eventName].push(handler);
      },
      emit(eventName, ...args) {
        this.events[eventName]?.forEach(handler => handler(...args));
      }
    };

    // 原updateElementBounds逻辑
    const updateElementBounds = () => {
      if (rootEl.value) {
        const { offsetTop, offsetHeight } = rootEl.value;
        elementTop.value = offsetTop;
        elementHeight.value = offsetHeight;
      }
    };

    // 绑定事件(替代原created中的$on)
    eventBus.on('update-visibility', updateElementBounds);

    // 若需内部触发事件,调用eventBus.emit('update-visibility')即可

    // 渲染函数
    return () => h('div', { ref: rootEl }, [
      slots.default?.({
        isPageFocused: props.isPageFocused,
        isElementFocused: props.isElementFocused
      })
    ]);
  }
};

方案二:使用mitt事件库

如果需要更完善的事件处理能力,可以引入mitt库:

  1. 安装mitt:
npm install mitt
  1. 组件代码:
import { ref, h } from 'vue';
import mitt from 'mitt';

export default {
  setup(props, { slots }) {
    const elementTop = ref(0);
    const elementHeight = ref(0);
    const rootEl = ref(null);

    // 创建mitt实例
    const emitter = mitt();

    const updateElementBounds = () => {
      if (rootEl.value) {
        const { offsetTop, offsetHeight } = rootEl.value;
        elementTop.value = offsetTop;
        elementHeight.value = offsetHeight;
      }
    };

    // 绑定事件
    emitter.on('update-visibility', updateElementBounds);

    // 内部触发事件示例:emitter.emit('update-visibility')

    // 渲染函数
    return () => h('div', { ref: rootEl }, [
      slots.default?.({
        isPageFocused: props.isPageFocused,
        isElementFocused: props.isElementFocused
      })
    ]);
  }
};

补充说明

  • 原代码中的this.$el在Vue3中通过ref绑定根元素获取,确保能正确访问DOM节点。
  • 若update-visibility事件由插槽内的子组件触发,可直接在插槽参数中传递回调函数,让子组件调用:
    // 渲染函数中修改slot参数
    slots.default?.({
      isPageFocused: props.isPageFocused,
      isElementFocused: props.isElementFocused,
      onUpdateVisibility: updateElementBounds // 传递回调给子组件
    })
    
    子组件内通过props.onUpdateVisibility()触发即可,无需使用事件发射器。

内容的提问来源于stack exchange,提问作者EXayer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 09:01:02