Vue.js reusable modal
by Michel Beloshitsky
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.17/vue.js "></script>
<modal-comment :show.sync="showModalComment"></modal-comment>
<button @click="showModalComment = true">Comment modal</button>
<template id="modal">
<div class="modal-mask" v-if="show" transition="modal" @click="close">
<div class="modal-container" @click.stop>
<slot></slot>
</div>
</div>
</template>
<template id="modal-comment">
<modal :show.sync="show" v-ref:modal-container>
<div class="modal-header">
<h3>Comment</h3>
</div>
<div class="modal-body">
<form>
<p>
<label>Comment</label>
<textarea rows="5"></textarea>
</p>
</form>
</div>
<div class="modal-footer">
<button @click="save()">Save comment</button>
</div>
</modal>
</template>
CSS
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, .7);
transition: opacity .3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.modal-container {
min-width: 50vw;
max-width: 80vw;
max-height: 80vh;
padding: 20px 30px;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
transition: all .3s ease;
overflow: auto;
}
.modal-body {
margin: 20px 0;
}
.modal-enter,
.modal-leave {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave .modal-container {
transform: scale(1.1);
}
JavaScript
const Modal = Vue.extend({
props: {
'show': {
type: Boolean,
required: true,
},
},
methods: {
close: function() {
this.show = false
},
},
ready: function() {
const self = this
document.addEventListener('keydown', function() {
if (self.show && event.keyCode === 27) { // Close the modal when the escape key is pressed.
self.close()
}
})
},
template: "#modal",
})
const ModalComment = Vue.extend({
props: ['show'],
components: {
'modal': Modal,
},
methods: {
close: function() {
this.$refs.modalContainer.close()
},
save: function() {
// TODO: implement the form logic and an XHR call as soon as the backend is operational.
this.close()
},
},
template: "#modal-comment",
})
new Vue({
el: 'body',
data: {
showModalComment: false,
},
components: {
'ModalComment': ModalComment,
},
})