Files
vue-js-modal/Modal/Modal.vue
2017-03-10 16:25:29 +00:00

258 lines
5.8 KiB
Vue

<template>
<transition name="overlay-fade">
<div v-if="visibility.overlay"
class="nice-modal-overlay"
@mousedown.stop="toggle(false)">
<transition :name="transition">
<div v-if="visibility.modal"
v-bind:class="modalClass"
v-bind:style="modalStyle"
v-on:mousedown.stop
ref="modal">
<slot></slot>
<resizer v-if="resizable"
:min-width="minWidth"
:min-height="minHeight"
@resize="resize"/>
</div>
</transition>
</div>
</transition>
</template>
<script>
import Vue from 'vue';
import Modal from './index';
import Resizer from './Resizer.vue';
export default {
name: 'Modal',
props: {
name: {
required: true,
type: [String, Number],
},
delay: {
type: Number,
default: 0,
},
resizable: {
type: Boolean,
default: false
},
adaptive: {
type: Boolean,
default: false
},
transition: {
type: String,
},
classes: {
type: [String, Array],
default: 'nice-modal',
},
width: {
type: Number,
default: 600
},
height: {
type: Number,
default: 300
},
minWidth: {
type: Number,
default: 0
},
minHeight: {
type: Number,
default: 0
}
},
components: {
Resizer
},
data() {
return {
visible: false,
visibility: {
modal: false,
overlay: false
},
modal: {
width: this.width,
height: this.height
},
window: {
width: window.innerWidth,
height: window.innerWidth
}
};
},
watch: {
visible(value) {
if (this.delay > 0) {
if (value) {
this.visibility.overlay = true;
setTimeout(() => this.visibility.modal = true, this.delay);
} else {
this.visibility.modal = false;
setTimeout(() => this.visibility.overlay = false, this.delay);
}
} else {
this.visibility.overlay = value;
Vue.nextTick(() => this.visibility.modal = value);
}
},
},
created() {
Modal.event.$on('toggle', (name, state, params) => {
if (name === this.name) {
this.toggle(!this.visible, params);
}
});
window.addEventListener('resize', this.onWindowResize);
},
beforeMount() {
this.onWindowResize();
},
computed: {
position() {
return {
left: Math.max((this.window.width - this.modal.width) / 2, 0),
top: Math.max((this.window.height - this.modal.height) / 2, 0)
}
},
modalClass() {
return ['modal', this.classes];
},
modalStyle() {
return {
top: this.position.top + 'px',
left: this.position.left + 'px',
width: this.modal.width + 'px',
height: this.modal.height + 'px'
}
}
},
methods: {
onWindowResize() {
this.window.width = window.innerWidth;
this.window.height = window.innerHeight;
if (this.adaptive) {
var width = this.window.width > this.modal.width
? this.modal.width
: this.window.width
var height = this.window.height > this.modal.height
? this.modal.height
: this.window.height;
this.modal.width = width;//Math.max(width, this.minWidth);
this.modal.height = height;//Math.max(height, this.minHeight);
}
},
genEventObject(params) {
return Vue.util.extend(
{
name: this.name,
ref: this.$refs.modal,
timestamp: Date.now()
},
params || {});
},
resize(event) {
this.modal.width = event.size.width;
this.modal.height = event.size.height;
let resizeEvent = this.genEventObject({
size: this.modal
});
this.$emit('resize', resizeEvent);
},
toggle(state, params) {
const beforeEventName = this.visible ? 'before-close' : 'before-open';
const afterEventName = this.visible ? 'closed' : 'opened';
let stopEventExecution = false;
const beforeEvent = this.genEventObject({
stop: () => stopEventExecution = false,
state,
params
});
this.$emit(beforeEventName, beforeEvent);
if (!stopEventExecution) {
this.visible = !!state;
const afterEvent = this.genEventObject({
state,
params
});
this.$emit(afterEventName, afterEvent);
}
},
},
};
</script>
<style lang="scss" scoped>
.nice-modal-overlay {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.2);
z-index: 999;
opacity: 1;
.modal {
position: relative;
overflow: hidden;
box-sizing: border-box;
background-color: white;
}
}
.overlay-fade-enter-active, .overlay-fade-leave-active {
transition: all 0.2s;
}
.overlay-fade-enter, .overlay-fade-leave-active {
opacity: 0;
}
.nice-modal-fade-enter-active, .nice-modal-fade-leave-active {
transition: all 0.4s;
}
.nice-modal-fade-enter, .nice-modal-fade-leave-active {
opacity: 0;
transform: translateY(-20px);
}
.nice-modal {
background: white;
text-align: left;
border-radius: 3px;
box-shadow: 0 20px 60px -2px rgba(27, 33, 58, .4);
padding: 0;
&.nice-modal-fullscreen {
width: 100vw;
height: 100vh;
margin: 0;
left: 0;
top: 0;
}
}
</style>