element-plus/packages/utils/popup/usePopup.ts
余林夕 c2951875b3
feat(message-box): migrate MessageBox (#300)
* feat(message-box): migrate MessageBox

* refactor(message-box): import sleep from test-utils

* refactor(message-box): optimize props

* refactor(message-box): optimize message-box

* refactor(message-box): optimize message-box

* refactor(message-box): optimize message-box

* refactor(message-box): remove `removeClass` & `addClass`

* refactor(message-box): replace 'HTMLElement' with 'HTMLButtonElement'

* refactor(message-box): review optimize

* refactor(message-box): __test__ optimize

* refactor(message-box): replace addEvent with on and off

* refactor(message-box): remove doc

* feat(message-box): jest add @babel/plugin-proposal-class-properties

Co-authored-by: YuLinXi <yumengyuan@klicen.com>
2020-10-19 13:50:22 +08:00

207 lines
4.6 KiB
TypeScript

import {
nextTick,
reactive,
onBeforeMount,
onBeforeUnmount,
onMounted,
getCurrentInstance,
watch,
} from 'vue'
import PopupManager from '../popup-manager'
import getScrollBarWidth from '../scrollbar-width'
import { getStyle, addClass, removeClass, hasClass } from '../dom'
import isServer from '../isServer'
let idSeed = 1
let scrollBarWidth
export const usePopup1 = {
watch: {
visible(val) {
if (val) {
if (this._opening) return
if (!this.rendered) {
this.rendered = true
nextTick(() => {
this.open()
}).then(() => {
//
})
} else {
this.open()
}
} else {
this.close()
}
},
},
}
const usePopup = (props, doClose) => {
let _popupId
let _opening = false
let _closing = false
let vm
let _closeTimer = null
let _openTimer = null
const state = reactive<State>({
opened: false,
bodyPaddingRight: null,
computedBodyPaddingRight: 0,
withoutHiddenClass: true,
rendered: false,
visible: false,
})
onMounted(() => {
vm = getCurrentInstance()
})
onBeforeMount(() => {
_popupId = 'popup-' + idSeed++
PopupManager.register(_popupId, vm)
})
onBeforeUnmount(() => {
PopupManager.deregister(_popupId)
PopupManager.closeModal(_popupId)
restoreBodyStyle()
})
const doOpen = merProps => {
if (isServer) return
if (state.opened) return
_opening = true
const dom = vm.vnode.el
const modal = merProps.modal
const zIndex = merProps.zIndex
if (zIndex) {
PopupManager.zIndex = zIndex
}
if (modal) {
if (_closing) {
PopupManager.closeModal(_popupId)
_closing = false
}
PopupManager.openModal(_popupId, PopupManager.nextZIndex(), props.modalAppendToBody ? undefined : dom, merProps.modalClass, merProps.modalFade)
if (merProps.lockScroll) {
state.withoutHiddenClass = !hasClass(document.body, 'el-popup-parent--hidden')
if (state.withoutHiddenClass) {
state.bodyPaddingRight = document.body.style.paddingRight
state.computedBodyPaddingRight = parseInt(getStyle(document.body, 'paddingRight'), 10)
}
scrollBarWidth = getScrollBarWidth()
const bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight
const bodyOverflowY = getStyle(document.body, 'overflowY')
if (scrollBarWidth > 0 && (bodyHasOverflow || bodyOverflowY === 'scroll') && state.withoutHiddenClass) {
document.body.style.paddingRight = state.computedBodyPaddingRight + scrollBarWidth + 'px'
}
addClass(document.body, 'el-popup-parent--hidden')
}
}
if (getComputedStyle(dom).position === 'static') {
dom.style.position = 'absolute'
}
dom.style.zIndex = PopupManager.nextZIndex()
state.opened = true
doAfterOpen()
}
const open = function (options?) {
if (!state.rendered) {
state.rendered = true
}
const _props = Object.assign({}, props || vm.proxy, options)
if (_closeTimer) {
clearTimeout(_closeTimer)
_closeTimer = null
}
clearTimeout(_openTimer)
const openDelay = Number(_props.openDelay)
if (openDelay > 0) {
_openTimer = setTimeout(() => {
_openTimer = null
doOpen(_props)
}, openDelay)
} else {
doOpen(_props)
}
}
const close = () => {
if (_openTimer !== null) {
clearTimeout(_openTimer)
_openTimer = null
}
clearTimeout(_closeTimer)
const closeDelay = Number(props.closeDelay)
if (closeDelay > 0) {
_closeTimer = setTimeout(() => {
_closeTimer = null
doClose()
}, closeDelay)
} else {
doClose()
}
}
const doAfterOpen = () => {
_opening = false
}
const restoreBodyStyle = () => {
if (props.modal && state.withoutHiddenClass) {
document.body.style.paddingRight = state.bodyPaddingRight
removeClass(document.body, 'el-popup-parent--hidden')
}
state.withoutHiddenClass = true
}
const doAfterClose = () => {
PopupManager.closeModal(_popupId)
_closing = false
}
const updateClosingFlag = value => {
_closing = value
}
watch(() => state.visible, async val => {
if (val) {
if (_opening) return
if (!state.rendered) {
state.rendered = true
await nextTick()
open()
} else {
open()
}
} else {
close()
}
})
return {
state,
close,
doAfterClose,
updateClosingFlag,
restoreBodyStyle,
}
}
export default usePopup