如何在Vue3中使用createVNode传递跨组件方法?

在vue3中使用createVNode挂载组件,组件本身的有一个需要传递一个跨组件的方法,如何把这个方法传给祖父组件。

// 被挂载的组件A
<script lang="ts" setup>
import { ref, onMounted, computed } from 'vue'
import mitt from 'mitt'

const emit = defineEmits(['configurationAckAlarm'])

// 确认告警
const ackedAlarm = (id: number, alarm: Alarm) => {
    let alarmData = JSON.parse(JSON.stringify(alarm))
    emit('configurationAckAlarm', alarmData)
}
</script>
// 挂载方法
const alarmInfoWindow = {}
let timer = null
/**
 * @param e 鼠标事件对象
 */
export function createAlarmInfoWindow(el, alarm) {
    const configMitt = mitt()

    const instance = createVNode(AlarmInfoWindow, {
        onConfigurationAckAlarm: (alarm) => {
            // 这样写外部无法接受到此方法
            configMitt.emit('handleConfigurationAckAlarm', alarm)
        }
    })

    e.target.onmouseleave = () => {
        closeAlarmInfoWindow(alarm)
    }

    instance.appContext = app._context
    render(instance, document.body)
    instance.el['onmouseover'] = () => {
        if (timer) clearTimeout(timer)
    }
    instance.el['onmouseleave'] = () => {
        closeAlarmInfoWindow(alarm)
    }

    alarmInfoWindow[alarm.id] = instance
    instance.remove = () => {
        document.body.removeChild(instance.el)
        render(null, document.body)
    }

    return instance.el
}

export function closeAlarmInfoWindow(alarm) {
    timer = setTimeout(() => {
        if (alarmInfoWindow[alarm.id]) {
            alarmInfoWindow[alarm.id].remove()
            delete alarmInfoWindow[alarm.id]
        }
    }, 300)
}
// 调用挂载方法的组件B
const showAlarmInfo = (event: MouseEvent, item) => {
    createAlarmInfoWindow(event, item)
}
// 组件B的父组件-组件C,也就是需要实现handleConfigurationAckAlarm,即configurationAckAlarm
const configMitt = mitt()
onMounted(() => {
    configMitt.on('handleConfigurationAckAlarm', (alarm) => {
// 监听不到组件A传来的方法
    })
})

组件C如何才能监听到组件A的configurationAckAlarm方法。

test

阅读 1.1k
avatarAI BotBETA
在 Vue 3 中使用 `createVNode` 传递跨组件方法时,你需要确保事件能够正确地通过中间组件(如组件B)传递到目标组件(如组件C)。在你的案例中,问题出在事件传递的方式上。组件A发出的事件应该能够被组件C捕获,但由于事件是在 `createAlarmInfoWindow` 函数内部通过 `mitt` 实例 `configMitt` 发射的,而这个 `configMitt` 实例与组件C中的 `configMitt` 实例不是同一个,因此事件无法正确传递。

为了解决这个问题,你可以采取以下几种方法之一:

1. **使用全局事件总线**:
   确保组件A、B、C都使用同一个事件总线实例。你可以将事件总线实例提升到一个更高的作用域(比如全局变量或Vue应用的根实例),然后在所有需要的组件中引用它。

2. **通过props传递回调函数**:
   如果可能的话,你可以尝试通过props将回调函数从组件C传递到组件B,然后再从组件B传递到组件A。当组件A触发事件时,它可以直接调用这个回调函数,而不是通过事件总线。

3. **使用Vuex或Pinia等状态管理库**:
   如果你的应用已经在使用Vuex或Pinia等状态管理库,你可以考虑将这类跨组件通信的逻辑放入状态管理中。

对于你的具体代码,如果选择使用全局事件总线,你可以修改如下:

- 在一个全局的地方(比如一个单独的文件)创建并导出一个 `mitt` 实例。
- 在组件A、B、C中都使用这个全局的 `mitt` 实例。

示例代码如下:

// eventBus.js
import mitt from 'mitt';
export const eventBus = mitt();

// 组件A
<script lang="ts" setup>
import { defineEmits } from 'vue';
import { eventBus } from './eventBus'; // 引入全局事件总线

const emit = defineEmits(['configurationAckAlarm']);

const ackedAlarm = (id: number, alarm: Alarm) => {

let alarmData = JSON.parse(JSON.stringify(alarm));
emit('configurationAckAlarm', alarmData);
eventBus.emit('handleConfigurationAckAlarm', alarmData); // 使用全局事件总线发射事件

};
</script>

// 组件C
<script lang="ts" setup>
import { onMounted } from 'vue';
import { eventBus } from './eventBus'; // 引入全局事件总线

onMounted(() => {

eventBus.on('handleConfigurationAckAlarm', (alarm) => {
    // 现在可以监听到组件A传来的事件了
});

});
</script>


注意,使用全局事件总线可能会导致事件管理变得复杂,特别是在大型应用中。因此,在使用之前请权衡利弊。
1 个回答

1.在组件B中传递事件处理函数:

// 调用挂载方法的组件B
const showAlarmInfo = (event: MouseEvent, item) => {
    createAlarmInfoWindow(event, item, handleConfigurationAckAlarm)
}

// 组件B的父组件-组件C
const configMitt = mitt()

const handleConfigurationAckAlarm = (alarm) => {
    configMitt.emit('handleConfigurationAckAlarm', alarm)
}

onMounted(() => {
    configMitt.on('handleConfigurationAckAlarm', (alarm) => {
        // 监听到组件A传来的方法
        console.log('Received alarm:', alarm)
    })
})

2.修改createAlarmInfoWindow函数以接受事件处理函数:

export function createAlarmInfoWindow(el, alarm, handleConfigurationAckAlarm) {
    const configMitt = mitt()

    const instance = createVNode(AlarmInfoWindow, {
        onConfigurationAckAlarm: (alarm) => {
            // 传递事件处理函数
            handleConfigurationAckAlarm(alarm)
        }
    })

    el.onmouseleave = () => {
        closeAlarmInfoWindow(alarm)
    }

    instance.appContext = app._context
    render(instance, document.body)
    instance.el.onmouseover = () => {
        if (timer) clearTimeout(timer)
    }
    instance.el.onmouseleave = () => {
        closeAlarmInfoWindow(alarm)
    }

    alarmInfoWindow[alarm.id] = instance
    instance.remove = () => {
        document.body.removeChild(instance.el)
        render(null, document.body)
    }

    return instance.el
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏