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 = export const clickOutside =
({ parent, props, state }: Pick<ISearchRenderlessParams, 'parent' | 'props' | 'state'>) => ({ parent, props, state }: Pick<ISearchRenderlessParams, 'parent' | 'props' | 'state'>) =>
(event: Event) => { (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 state.show = false
props.mini && !state.currentValue && (state.collapse = true) props.mini && !state.currentValue && (state.collapse = true)
} }

View File

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