|
|
@@ -1,20 +1,32 @@
|
|
|
<template>
|
|
|
- <transition :name="transitionName">
|
|
|
+ <transition
|
|
|
+ :name="transitionName"
|
|
|
+ @after-enter="$emit('opened')"
|
|
|
+ @after-leave="$emit('closed')"
|
|
|
+ >
|
|
|
<div
|
|
|
ref="popupBox"
|
|
|
v-show="value"
|
|
|
class="popup-box"
|
|
|
:class="[`popup-${position}`, { round }]"
|
|
|
+ @click="$emit('click', this)"
|
|
|
>
|
|
|
- <slot></slot>
|
|
|
- <nut-icon v-if='closeable' @click.native='$emit("input", false)' :type="closeIcon" size="12px" class="nutui-popup__close-icon" :class="'nutui-popup__close-icon--'+closeIconPosition">
|
|
|
- </nut-icon>
|
|
|
+ <slot></slot>
|
|
|
+ <nut-icon
|
|
|
+ v-if="closeable"
|
|
|
+ @click.native="$emit('input', false)"
|
|
|
+ :type="closeIcon"
|
|
|
+ size="12px"
|
|
|
+ class="nutui-popup__close-icon"
|
|
|
+ :class="'nutui-popup__close-icon--' + closeIconPosition"
|
|
|
+ >
|
|
|
+ </nut-icon>
|
|
|
</div>
|
|
|
</transition>
|
|
|
</template>
|
|
|
<script>
|
|
|
import Vue from "vue";
|
|
|
-import Mask from "./mask.vue";
|
|
|
+import overlay from "./overlay.vue";
|
|
|
|
|
|
export default {
|
|
|
name: "nut-popup",
|
|
|
@@ -30,20 +42,38 @@ export default {
|
|
|
type: Boolean,
|
|
|
default: true
|
|
|
},
|
|
|
- closeable:{
|
|
|
- type: Boolean,
|
|
|
- default: false
|
|
|
+ closeable: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
},
|
|
|
closeIconPosition: {
|
|
|
type: String,
|
|
|
- default: 'top-right'
|
|
|
+ default: "top-right"
|
|
|
+ },
|
|
|
+ closeIcon: {
|
|
|
+ type: String,
|
|
|
+ default: "cross"
|
|
|
+ },
|
|
|
+ lockScroll:{
|
|
|
+ type:Boolean,
|
|
|
+ default:true
|
|
|
+ },
|
|
|
+ closeOnClickOverlay:{
|
|
|
+ type:Boolean,
|
|
|
+ default:true
|
|
|
+ },
|
|
|
+ overlayClass: {
|
|
|
+ type:String,
|
|
|
+ default:""
|
|
|
},
|
|
|
- closeIcon:{
|
|
|
- type: String,
|
|
|
- default: 'cross'
|
|
|
+ overlayStyle: {
|
|
|
+ type:String,
|
|
|
+ default:""
|
|
|
},
|
|
|
+ getContainer:String,
|
|
|
round: Boolean
|
|
|
},
|
|
|
+ beforeCreate() {},
|
|
|
created() {
|
|
|
if (this.transition) {
|
|
|
this.transitionName = this.transition;
|
|
|
@@ -56,6 +86,12 @@ export default {
|
|
|
mounted() {
|
|
|
if (this.duration) {
|
|
|
this.$refs.popupBox.style.transitionDuration = this.duration + "s";
|
|
|
+ }
|
|
|
+ if (this.getContainer) {
|
|
|
+ this.portal();
|
|
|
+ }
|
|
|
+ if (this.value) {
|
|
|
+ this.open();
|
|
|
}
|
|
|
},
|
|
|
watch: {
|
|
|
@@ -69,16 +105,16 @@ export default {
|
|
|
} else {
|
|
|
this.transitionName = `popup-slide-${this.position}`;
|
|
|
}
|
|
|
- }
|
|
|
+ },
|
|
|
+ getContainer: 'portal'
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
transitionName: "popup-fade",
|
|
|
- maskInstant: null
|
|
|
+ overlayInstant: null
|
|
|
};
|
|
|
},
|
|
|
-
|
|
|
- methods: {
|
|
|
+ methods: {
|
|
|
mount(Component, data) {
|
|
|
const instance = new Vue({
|
|
|
el: document.createElement("div"),
|
|
|
@@ -90,26 +126,70 @@ export default {
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
- document.body.appendChild(instance.$el);
|
|
|
+ const el = this.$refs.popupBox;
|
|
|
+ if (el && el.parentNode) {
|
|
|
+ el.parentNode.insertBefore(instance.$el, el);
|
|
|
+ } else {
|
|
|
+ document.body.appendChild(instance.$el);
|
|
|
+ }
|
|
|
return instance;
|
|
|
},
|
|
|
|
|
|
open() {
|
|
|
- if (!this.maskInstant) {
|
|
|
- this.maskInstant = this.mount(Mask, {
|
|
|
+ if (!this.overlayInstant) {
|
|
|
+ this.overlayInstant = this.mount(overlay, {
|
|
|
+ className: this.overlayClass,
|
|
|
+ customStyle: this.overlayStyle,
|
|
|
nativeOn: {
|
|
|
click: () => {
|
|
|
- this.$emit("input", false);
|
|
|
+ this.$emit("click-overlay", this);
|
|
|
+ if(this.closeOnClickOverlay){
|
|
|
+ this.$emit("input", false);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
- this.maskInstant.show = true;
|
|
|
+ this.overlayInstant.show = true;
|
|
|
}
|
|
|
+
|
|
|
+ if (this.lockScroll && !this.locked) {
|
|
|
+
|
|
|
+ document.body.classList.add('nut-overflow-hidden');
|
|
|
+ this.locked = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.$emit("open", this);
|
|
|
},
|
|
|
close() {
|
|
|
- this.maskInstant.show = false;
|
|
|
- }
|
|
|
+ this.overlayInstant.show = false;
|
|
|
+ if (this.lockScroll && this.locked) {
|
|
|
+ document.body.classList.remove('nut-overflow-hidden');
|
|
|
+ this.locked = false;
|
|
|
+ }
|
|
|
+ this.$emit("close", this);
|
|
|
+ },
|
|
|
+ getElement(selector){
|
|
|
+ if (typeof selector === "string") {
|
|
|
+ return document.querySelector(selector);
|
|
|
+ }
|
|
|
+ return selector();
|
|
|
+ },
|
|
|
+ portal() {
|
|
|
+ const { getContainer } = this;
|
|
|
+ const el = this.$el;
|
|
|
+
|
|
|
+ let container;
|
|
|
+ if (getContainer) {
|
|
|
+ container = this.getElement(getContainer);
|
|
|
+ } else if (this.$parent) {
|
|
|
+ container = this.$parent.$el;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (container && container !== el.parentNode) {
|
|
|
+ container.appendChild(el);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
</script>
|