programmatic modal with store
HTML
<script src="https://unpkg.com/[email protected]"></script>
<div id="app">
<button class="button" @click="openModal()">Open Modal</button>
<button class="button" @click="openStoreModal()">Open Store Modal</button>
<button class="button" @click="openParentModal()">Open Parent Modal</button>
</div>
<template id="sampleModal">
<div class="modal-card">
<div class="modal-card-head">
<p class="modal-card-title">Title</p>
</div>
<div class="modal-card-foot">
<button class="button" :class="{'is-loading': isLoading}" @click="$emit('close')">Close</button>
</div>
</div>
</template>
<template id="modal">
<div class="modal is-active">
<div class="modal-background" @click="close()"></div>
<div class="modal-content animation-content">
<component :is="component" @close="close()"></component>
</div>
</div>
</template>
CSS
@import url("//unpkg.com/buefy/lib/buefy.css");
JavaScript
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
loading: 0
},
getters: {
isLoading({loading}) {
return !!loading
}
},
mutations: {
startLoading(state) {
state.loading++
},
stopLoading(state) {
state.loading--
}
}
})
class Modal {
constructor() {
this.modal = {
template: '#modal',
props: {
component: Object
},
methods: {
close() {
setTimeout(() => {
this.$destroy()
this.$el.remove()
}, 150)
}
},
beforeMount() {
document.body.appendChild(this.$el)
}
}
}
open(params) {
const propsData = Object.assign({}, params)
const ModalComponent = Vue.extend(this.modal)
return new ModalComponent({
el: document.createElement('div'),
propsData
})
}
openWithStore(params) {
const propsData = Object.assign({}, params)
const ModalComponent = Vue.extend(this.modal)
return new ModalComponent({
el: document.createElement('div'),
propsData,
store
})
}
openWithParent(params) {
const propsData = Object.assign({}, params)
const ModalComponent = Vue.extend(this.modal)
return new ModalComponent({
el: document.createElement('div'),
propsData,
parent
})
}
}
Vue.use({
install(Vue) {
const modal = new Modal
Object.defineProperties(Vue.prototype, {
$modal: {
get() {
return modal
}
}
})
}
})
const sampleModal = {
template: '#sampleModal',
created() {
this.$store.commit('startLoading')
},
mounted() {
setTimeout(() => {
this.$store.commit('stopLoading')
}, 1000)
},
computed: {
isLoading() {
return this.$store.getters.isLoading
}
}
}
const parent = new Vue({
el: '#app',
store,
methods: {
openModal() {
this.$modal.open({
component: sampleModal
})
},
openStoreModal() {
...