naive-ui/packages/utils/moveoutsideDelegate.js
07akioni ffad17ff1f fix(popover): some times it can't disappear normally when mouseleave
mouseleave event sometimes can't fire. So I detect mouseout outside the popover
and activator to make it disappear. Implementation has many tricks. Sigh, life
is so hard.
2019-07-18 00:32:01 +08:00

69 lines
2.0 KiB
JavaScript

class MoveOutsideDelegate {
constructor () {
console.debug('[MoveOutsideDelegate]: Ctor called')
this.handlers = new Map()
this.handlerCount = 0
this.handleMoveOutside = this.handleMoveOutside.bind(this)
}
handleMoveOutside (e) {
const target = e.target
for (const [handler, { els, once }] of this.handlers) {
let existElContainTarget = false
for (const el of els) {
if (el) {
if (typeof el === 'function') {
const unwrappedEl = el()
if (unwrappedEl && unwrappedEl.contains(target)) {
existElContainTarget = true
break
}
} else if (el.contains(target)) {
existElContainTarget = true
break
}
}
}
if (existElContainTarget) continue
else {
handler(e)
if (once) {
this.unregisterHandler(handler)
}
}
}
}
unregisterHandler (handler) {
console.debug('[MoveOutsideDelegate]: unregisterHandler')
const h = this.handlers.get(handler)
if (h) {
this.handlers.delete(handler)
--this.handlerCount
}
if (!this.handlerCount) {
console.debug('[MoveOutsideDelegate]: remove handler from window')
window.removeEventListener('mousemove', this.handleMoveOutside, true)
this.handlers = new Map()
}
}
registerHandler (els, handler, once = true) {
if (!Array.isArray(els)) {
els = [els]
}
for (const el of els) {
if (!el) throw new Error('[MoveOutsideDelegate.registerHandler]: make sure `el` is an HTMLElement')
}
if (this.handlers.get(handler)) {
this.handlers.set(handler, { els, once })
return
}
if (!this.handlerCount) {
console.debug('[MoveOutsideDelegate]: add handler to window')
window.addEventListener('mousemove', this.handleMoveOutside, true)
}
++this.handlerCount
this.handlers.set(handler, { els, once })
}
}
export default new MoveOutsideDelegate()