Vue 3实现通用弹窗组件时slot绑定click事件不触发如何解决
问题原因
<slot>是Vue的内容分发占位符,本身不会渲染为真实DOM节点,所以直接绑定在<slot>标签上的事件、类名、属性都不会生效,这是问题出现的根本原因。
解决方案
方案1:使用@click.self修饰符(最简方案)
不需要额外添加DOM元素,也不需要编写阻止冒泡的方法,直接给外层遮罩层的点击事件添加.self修饰符即可,该修饰符会限制事件仅在点击元素本身时触发,点击内部slot内容时不会触发关闭逻辑:
<template> <teleport to="body"> <div class="modal-window" @click.self="close" v-show="isOpened"> <slot></slot> </div> </teleport> </template>
方案2:slot外层包裹容器元素(最通用方案)
这个方案是业务开发中最常用的最优解,额外的容器层几乎不会带来性能损耗,同时还可以统一控制弹窗内容的基础样式(比如宽度、内边距、背景、圆角等),提升组件通用性:
<template> <teleport to="body"> <div class="modal-window" @click="close" v-show="isOpened"> <div class="modal-window__content" @click.stop> <slot></slot> </div> </div> </teleport> </template>
提示:可以直接用
.stop修饰符代替手动写event.stopPropagation()的contentClick方法,进一步精简代码。
方案选型建议
- 如果你的弹窗组件不需要统一管控内容区域的基础样式,优先选方案1,代码最精简
- 如果需要统一设置内容区域的通用样式、或者需要做内容区域的统一逻辑管控(比如统一加关闭按钮、拖拽逻辑等),优先选方案2,可维护性更高
内容的提问来源于stack exchange,提问作者Alex White
相关产品推荐
相关产品推荐

