<template> <div class="mk-popup"> <transition name="bg-fade" appear> <div class="bg" ref="bg" @click="close()" v-if="show"></div> </transition> <transition name="popup" appear @after-leave="() => { $emit('closed'); destroyDom(); }"> <div class="content" :class="{ fixed }" ref="content" v-if="show" :style="{ width: width ? width + 'px' : 'auto' }"><slot></slot></div> </transition> </div> </template> <script lang="ts"> import Vue from 'vue'; export default Vue.extend({ props: { source: { required: true }, noCenter: { type: Boolean, required: false }, fixed: { type: Boolean, required: false }, width: { type: Number, required: false } }, data() { return { show: true, }; }, mounted() { this.$nextTick(() => { const popover = this.$refs.content as any; const rect = this.source.getBoundingClientRect(); const width = popover.offsetWidth; const height = popover.offsetHeight; let left; let top; if (this.$root.isMobile && !this.noCenter) { const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.source.offsetWidth / 2); const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + (this.source.offsetHeight / 2); left = (x - (width / 2)); top = (y - (height / 2)); popover.style.transformOrigin = 'center'; } else { const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.source.offsetWidth / 2); const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + this.source.offsetHeight; left = (x - (width / 2)); top = y; } if (this.fixed) { if (left + width > window.innerWidth) { left = window.innerWidth - width; popover.style.transformOrigin = 'center'; } if (top + height > window.innerHeight) { top = window.innerHeight - height; popover.style.transformOrigin = 'center'; } } else { if (left + width - window.pageXOffset > window.innerWidth) { left = window.innerWidth - width + window.pageXOffset; popover.style.transformOrigin = 'center'; } if (top + height - window.pageYOffset > window.innerHeight) { top = window.innerHeight - height + window.pageYOffset; popover.style.transformOrigin = 'center'; } } if (top < 0) { top = 0; } if (left < 0) { left = 0; } popover.style.left = left + 'px'; popover.style.top = top + 'px'; }); }, methods: { close() { this.show = false; (this.$refs.bg as any).style.pointerEvents = 'none'; (this.$refs.content as any).style.pointerEvents = 'none'; } } }); </script> <style lang="scss" scoped> .popup-enter-active, .popup-leave-active { transition: opacity 0.3s, transform 0.3s !important; } .popup-enter, .popup-leave-to { opacity: 0; transform: scale(0.9); } .bg-fade-enter-active, .bg-fade-leave-active { transition: opacity 0.3s !important; } .bg-fade-enter, .bg-fade-leave-to { opacity: 0; } .mk-popup { > .bg { position: fixed; top: 0; left: 0; z-index: 10000; width: 100%; height: 100%; background: var(--modalBg) } > .content { position: absolute; z-index: 10001; background: var(--panel); border-radius: 4px; box-shadow: 0 3px 12px rgba(27, 31, 35, 0.15); overflow: hidden; transform-origin: center top; &.fixed { position: fixed; } } } </style>