Seems easy enough, right? Let’s glance over different solutions I harbored.
For this solution we create invisible overlay over a whole window. Overlay catches all clicks.
<div class="full-screen-overlay-modal">
<div class="background"
@click="hide()"
v-if="isDisplayed"
/>
<div class="content"
v-if="isDisplayed"
>
<slot></slot>
</div>
</div>
gistfile1.html
full-screen-overlay-modal {
&__background {
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
&__content {
position: fixed;
z-index: 2000;
// Closing multiple modals won't work without this line. No idea as to why.
transform: translateY(4px);
}
}
gistfile1.scss
Looks fine, doesn’t it? Except that it’s blocking… Which means that, in order to open another modal, a user has to close the current one. That’s 2 actions and we can do better.
Here’s the component code.
For this approach we attach a click event handler to document.body
, we also prevent click event propagation on modal click.
<div class="document-event-modal">
<div class="document-event-modal__content"
@click.stop
v-if="isDisplayed"
>
<slot></slot>
</div>
</div>
gistfile1.html
// ...
methods: {
show () {
this.isDisplayed = true
this.$emit('input', true)
this.listen(true)
},
hide () {
this.isDisplayed = false
this.$emit('input', false)
this.listen(false)
},
listen (on: Boolean = true) {
// So that we won't add or remove same listener twice
if (this.isListening === on) {
return
}
// Adding or removing listeners.
if (on) {
setTimeout(() => {
document.body.addEventListener('click', this.hide, false)
})
} else {
document.body.removeEventListener('click', this.hide, false)
}
// Flag to know if listener is already registered.
this.isListening = on
}
},
// ...
gistfile1.js
The downside is that any other modal will prevent bubbling to document
.
Meaning no nesting ¯\_(ツ)_/¯
.
Here’s the component code.
Ok. This is an ultimate solution. For the most part it’s the same as a previous one. Only that we won’t prevent propagation. And instead we’ll check the event.target
.
Template is regular. Nothing special here.
<div class="click-target-modal">
<div class="click-target-modal__content"
v-if="isDisplayed"
>
<slot></slot>
</div>
</div>
gistfile1.html
We check, if a click landed on a child. In case it didn’t — modal hides itself.
import DomHelpers from './Utility/DomHelpers.js'
// ...
methods: {
click (event) {
DomHelpers.isChild(this.$el, event.target) || this.hide()
},
}
gistfile1.js
Here’s the component code.
Let’s test our modal.
Done.
Check the source code if you’re looking for complete components.
Tell me if anything is wrong or this modal is not nearly perfect in your opinion. : 3
If you like what you just read, please subscribe to our newsletter to get more content from Epicmax and bonus code that will give you a discount for first 30 days working with us.
Recommended Courses:
Build Web Apps with Vue JS 2 & Firebase
☞ http://bit.ly/2NMsDy9
Building a TodoMVC Application in Vue, React and Angular
☞ http://bit.ly/2LuFZSV
Vue JS 2: From Beginner to Professional (includes Vuex)
☞ http://bit.ly/2v4gL2L
Vue JS Essentials with Vuex and Vue Router
☞ http://bit.ly/2vjVMJ8
☞ JavaScript Programming Tutorial Full Course for Beginners
☞ JavaScript for React Developers | Mosh
☞ Top 4 Programming Languages to Learn in 2019 to Get a Job
☞ Learn JavaScript - Become a Zero to Hero
☞ Javascript Project Tutorial: Budget App
☞ E-Commerce JavaScript Tutorial - Shopping Cart from Scratch