fix:修复shadowRoot节点下组件事件失效 (#3546)
This commit is contained in:
parent
a56006ba2d
commit
9bebc671ea
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
* 两个修饰符,mousedown、mouseup
|
|
||||||
* 当没有修饰符时,需要同时满足在目标元素外同步按下和释放鼠标才会触发回调。
|
* 当没有修饰符时,需要同时满足在目标元素外同步按下和释放鼠标才会触发回调。
|
||||||
* ```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]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue