mirror of https://github.com/ElemeFE/element
273 lines
6.0 KiB
JavaScript
273 lines
6.0 KiB
JavaScript
import Vue from 'vue';
|
|
import merge from 'element-ui/src/utils/merge';
|
|
import PopupManager from 'element-ui/src/utils/popup/popup-manager';
|
|
import getScrollBarWidth from '../scrollbar-width';
|
|
|
|
let idSeed = 1;
|
|
const transitions = [];
|
|
|
|
const hookTransition = (transition) => {
|
|
if (transitions.indexOf(transition) !== -1) return;
|
|
|
|
const getVueInstance = (element) => {
|
|
let instance = element.__vue__;
|
|
if (!instance) {
|
|
const textNode = element.previousSibling;
|
|
if (textNode.__vue__) {
|
|
instance = textNode.__vue__;
|
|
}
|
|
}
|
|
return instance;
|
|
};
|
|
|
|
Vue.transition(transition, {
|
|
afterEnter(el) {
|
|
const instance = getVueInstance(el);
|
|
|
|
if (instance) {
|
|
instance.doAfterOpen && instance.doAfterOpen();
|
|
}
|
|
},
|
|
afterLeave(el) {
|
|
const instance = getVueInstance(el);
|
|
|
|
if (instance) {
|
|
instance.doAfterClose && instance.doAfterClose();
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
let scrollBarWidth;
|
|
|
|
const getDOM = function(dom) {
|
|
if (dom.nodeType === 3) {
|
|
dom = dom.nextElementSibling || dom.nextSibling;
|
|
getDOM(dom);
|
|
}
|
|
return dom;
|
|
};
|
|
|
|
export default {
|
|
props: {
|
|
visible: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
transition: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
openDelay: {},
|
|
closeDelay: {},
|
|
zIndex: {},
|
|
modal: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
modalFade: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
modalClass: {},
|
|
modalAppendToBody: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
lockScroll: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
closeOnPressEscape: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
closeOnClickModal: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
},
|
|
|
|
created() {
|
|
if (this.transition) {
|
|
hookTransition(this.transition);
|
|
}
|
|
},
|
|
|
|
beforeMount() {
|
|
this._popupId = 'popup-' + idSeed++;
|
|
PopupManager.register(this._popupId, this);
|
|
},
|
|
|
|
beforeDestroy() {
|
|
PopupManager.deregister(this._popupId);
|
|
PopupManager.closeModal(this._popupId);
|
|
if (this.modal && this.bodyOverflow !== null && this.bodyOverflow !== 'hidden') {
|
|
document.body.style.overflow = this.bodyOverflow;
|
|
document.body.style.paddingRight = this.bodyPaddingRight;
|
|
}
|
|
this.bodyOverflow = null;
|
|
this.bodyPaddingRight = null;
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
opened: false,
|
|
bodyOverflow: null,
|
|
bodyPaddingRight: null,
|
|
rendered: false
|
|
};
|
|
},
|
|
|
|
watch: {
|
|
visible(val) {
|
|
if (val) {
|
|
if (this._opening) return;
|
|
if (!this.rendered) {
|
|
this.rendered = true;
|
|
Vue.nextTick(() => {
|
|
this.open();
|
|
});
|
|
} else {
|
|
this.open();
|
|
}
|
|
} else {
|
|
this.close();
|
|
}
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
open(options) {
|
|
if (!this.rendered) {
|
|
this.rendered = true;
|
|
}
|
|
|
|
const props = merge({}, this.$props || this, options);
|
|
|
|
if (this._closeTimer) {
|
|
clearTimeout(this._closeTimer);
|
|
this._closeTimer = null;
|
|
}
|
|
clearTimeout(this._openTimer);
|
|
|
|
const openDelay = Number(props.openDelay);
|
|
if (openDelay > 0) {
|
|
this._openTimer = setTimeout(() => {
|
|
this._openTimer = null;
|
|
this.doOpen(props);
|
|
}, openDelay);
|
|
} else {
|
|
this.doOpen(props);
|
|
}
|
|
},
|
|
|
|
doOpen(props) {
|
|
if (this.$isServer) return;
|
|
if (this.willOpen && !this.willOpen()) return;
|
|
if (this.opened) return;
|
|
|
|
this._opening = true;
|
|
|
|
const dom = getDOM(this.$el);
|
|
|
|
const modal = props.modal;
|
|
|
|
const zIndex = props.zIndex;
|
|
if (zIndex) {
|
|
PopupManager.zIndex = zIndex;
|
|
}
|
|
|
|
if (modal) {
|
|
if (this._closing) {
|
|
PopupManager.closeModal(this._popupId);
|
|
this._closing = false;
|
|
}
|
|
PopupManager.openModal(this._popupId, PopupManager.nextZIndex(), this.modalAppendToBody ? undefined : dom, props.modalClass, props.modalFade);
|
|
if (props.lockScroll) {
|
|
if (!this.bodyOverflow) {
|
|
this.bodyPaddingRight = document.body.style.paddingRight;
|
|
this.bodyOverflow = document.body.style.overflow;
|
|
}
|
|
scrollBarWidth = getScrollBarWidth();
|
|
let bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight;
|
|
if (scrollBarWidth > 0 && bodyHasOverflow) {
|
|
document.body.style.paddingRight = scrollBarWidth + 'px';
|
|
}
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
}
|
|
|
|
if (getComputedStyle(dom).position === 'static') {
|
|
dom.style.position = 'absolute';
|
|
}
|
|
|
|
dom.style.zIndex = PopupManager.nextZIndex();
|
|
this.opened = true;
|
|
|
|
this.onOpen && this.onOpen();
|
|
|
|
if (!this.transition) {
|
|
this.doAfterOpen();
|
|
}
|
|
},
|
|
|
|
doAfterOpen() {
|
|
this._opening = false;
|
|
},
|
|
|
|
close() {
|
|
if (this.willClose && !this.willClose()) return;
|
|
|
|
if (this._openTimer !== null) {
|
|
clearTimeout(this._openTimer);
|
|
this._openTimer = null;
|
|
}
|
|
clearTimeout(this._closeTimer);
|
|
|
|
const closeDelay = Number(this.closeDelay);
|
|
|
|
if (closeDelay > 0) {
|
|
this._closeTimer = setTimeout(() => {
|
|
this._closeTimer = null;
|
|
this.doClose();
|
|
}, closeDelay);
|
|
} else {
|
|
this.doClose();
|
|
}
|
|
},
|
|
|
|
doClose() {
|
|
this._closing = true;
|
|
|
|
this.onClose && this.onClose();
|
|
|
|
if (this.lockScroll) {
|
|
setTimeout(() => {
|
|
if (this.modal && this.bodyOverflow !== 'hidden') {
|
|
document.body.style.overflow = this.bodyOverflow;
|
|
document.body.style.paddingRight = this.bodyPaddingRight;
|
|
}
|
|
this.bodyOverflow = null;
|
|
this.bodyPaddingRight = null;
|
|
}, 200);
|
|
}
|
|
|
|
this.opened = false;
|
|
|
|
if (!this.transition) {
|
|
this.doAfterClose();
|
|
}
|
|
},
|
|
|
|
doAfterClose() {
|
|
PopupManager.closeModal(this._popupId);
|
|
this._closing = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
export {
|
|
PopupManager
|
|
};
|