fix:修复shadowRoot节点下组件事件失效 (#3546)

This commit is contained in:
liukun 2025-07-03 23:15:19 -07:00 committed by GitHub
parent a56006ba2d
commit 9bebc671ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 15 deletions

View File

@ -76,7 +76,11 @@ export const searchEnterKey =
export const clickOutside =
({ parent, props, state }: Pick<ISearchRenderlessParams, 'parent' | 'props' | 'state'>) =>
(event: Event) => {
if (!parent.$el.contains(event.target)) {
// 优先使用 event.composedPath() 来判断事件源是否在组件内部,以兼容 Shadow DOM。
// 在 Shadow DOM 中,事件冒泡穿过 Shadow Root 后event.target 会被重定向为 host 元素,
// 导致传统的 contains 判断失效。composedPath 则能提供真实的事件路径。
const path = event.composedPath && event.composedPath()
if (path ? !path.includes(parent.$el) : !parent.$el.contains(event.target)) {
state.show = false
props.mini && !state.currentValue && (state.collapse = true)
}

View File

@ -35,16 +35,18 @@ if (!isServer) {
const createDocumentHandler = (el, binding, vnode) =>
function (mouseup = {}, mousedown = {}) {
let popperElm = vnode.context.popperElm || (vnode.context.state && vnode.context.state.popperElm)
const popperElm = vnode.context.popperElm || (vnode.context.state && vnode.context.state.popperElm)
if (
!mouseup?.target ||
!mousedown?.target ||
el.contains(mouseup.target) ||
el.contains(mousedown.target) ||
el === mouseup.target ||
(popperElm && (popperElm.contains(mouseup.target) || popperElm.contains(mousedown.target)))
) {
// 使用 event.composedPath() 来处理 Shadow DOM 场景。
// composedPath() 会返回事件的完整路径,即使事件穿过了 Shadow DOM 的边界。
// 这确保了即使 popperElm 在 Shadow DOM 外部(或组件本身在 Shadow DOM 内部),
// 我们也能准确判断点击是否发生在组件或其 popper 内部。
const mousedownPath = (mousedown?.composedPath && mousedown.composedPath()) || [mousedown?.target]
const mouseupPath = (mouseup?.composedPath && mouseup.composedPath()) || [mouseup.target]
const isClickInEl = mousedownPath.includes(el) || mouseupPath.includes(el)
const isClickInPopper = popperElm && (mousedownPath.includes(popperElm) || mouseupPath.includes(popperElm))
if (!mousedown.target || !mouseup.target || isClickInEl || isClickInPopper) {
return
}
@ -56,10 +58,6 @@ const createDocumentHandler = (el, binding, vnode) =>
}
/**
* v-clickoutside
* @desc
* @example
* mousedownmouseup
*
* ```html
* <div v-clickoutside="handleClose"> // 在元素外部点击时触发
@ -110,7 +108,6 @@ export default {
if (nodeList.length === 0 && startClick) {
startClick = null
}
delete el[nameSpace]
}
}