Nuxt 3如何获取插槽元素并触发VueUse的onClickOutside?
解决VueUse onClickOutside在Nuxt中无法获取插槽元素的问题
问题核心在于你直接将Vue的VNode对象传给了onClickOutside,但这个函数需要绑定真实DOM元素才能生效。在Vue3/Nuxt3中,this.$slots.default()[0]返回的是VNode(虚拟节点),不是渲染后的真实DOM,所以监听不会触发。
修复方案
通过ref获取插槽所在的真实DOM容器,再绑定onClickOutside:
Options API 写法
<template> <div class="flex flex-col items-center justify-center min-h-screen fixed inset-0 p-5 bg-gray-300/75 z-50"> <!-- 给插槽外层加容器并绑定ref --> <div ref="slotContent"> <slot /> </div> </div> </template> <script> import { onClickOutside } from '@vueuse/core' export default { mounted() { // 确保获取到真实DOM后再绑定监听 if (this.$refs.slotContent) { const stop = onClickOutside(this.$refs.slotContent, () => { this.$emit('close') }) // 组件卸载时清理监听,避免内存泄漏 this.$once('hook:beforeUnmount', stop) } } } </script>
Composition API(Nuxt3推荐)写法
<template> <div class="flex flex-col items-center justify-center min-h-screen fixed inset-0 p-5 bg-gray-300/75 z-50"> <div ref="slotContent"> <slot /> </div> </div> </template> <script setup> import { ref, onMounted, onUnmounted } from 'vue' import { onClickOutside } from '@vueuse/core' const slotContent = ref(null) let stopListener = null // 组件挂载后绑定监听 onMounted(() => { if (slotContent.value) { stopListener = onClickOutside(slotContent.value, () => { emit('close') }) } }) // 组件卸载时停止监听 onUnmounted(() => { stopListener?.() }) // 定义emit事件 const emit = defineEmits(['close']) </script>
关键说明
- VNode vs 真实DOM:Vue3的
$slots返回虚拟节点集合,无法直接用于DOM事件监听,必须通过ref获取渲染后的真实DOM元素。 - 监听清理:
onClickOutside会返回一个停止监听的函数,记得在组件卸载时调用,避免内存泄漏。 - 空插槽判断:加入
if判断防止插槽为空时出现null绑定报错。
内容的提问来源于stack exchange,提问作者Rahul Mukati
相关产品推荐
相关产品推荐

