Clicking on card not to do anything in vuejs

Issue

I have an overlay that when you click on it makes it disappear! I have an absolute positioned card on top of this overlay that when clicked on should not make the overlay disappear but it does. How can I make it so clicking on anywhere on the screen but the card makes the overlay disappear?

<div v-if="displayOverlay" class="overlay" @click="!displayOverlay">
  <div class="card"> Hello </div>
</div>

.card{
 position: absolute;
 bottom: 400px;
}

Solution

click event bubbles.

Practically, if a click is triggered on <Child /> in this structure:

<GrandParent>
  <Parent>
    <Child />
  </Parent>
</GrandParent>

, the event will fire on each element, in this order 1:

  • on Child
  • on Parent
  • on GrandParent
  • … on each of the consequent parents in DOM tree, all the way up to window object.

To prevent an event from bubbling you have to call its stopPropagation method. You can do this at any level, because the events described above are fired in sequence, not in parallel.

To prevent propagation to parents and also prevent any subsequent event handlers registered on the current element from being fired, call stopImmediatePropagation method on the event.

Vue provides event modifiers, significantly reducing the boilerplate typically associated with calling event native methods.

In your case, you have to use the .stop modifier on .card to prevent it from bubbling to .overlay:

<div v-if="displayOverlay" class="overlay" @click="displayOverlay = false">
  <div class="card" @click.stop> Hello </div>
</div>

Demo 2, 3:

new Vue({
  el: '#app',
  data: () => ({
    displayCard: true
  })
})
.overlay {
  position: absolute;
  background-color: rgba(0,0,0,.21);
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.card {
  height: 200px;
  width: 300px;
  padding: 1rem;
  background-color: white;
}
body {
  margin: 0;
}
#app {
 min-height: 100vh;
}
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<div id="app" @click="displayCard = true">
  <div class="overlay" v-if="displayCard" @click.stop="displayCard = false">
    <div class="card" @click.stop>Test</div>
  </div>
  <button v-if="!displayCard">Reopen overlay</button>
</div>

NOTES:

1 – the order above is the native firing order. Vue provides a modifier (.capture) which allows you to change it. Before starting to run the native sequence, Vue checks all parents (starting from window all the way down to the clicked element) and if any of them has the .capture modifier, their event handler will be run at that time (before running the handlers on any of its children). This doesn’t mean the event handler will run twice, though. If it has been run in capture phase, it won’t be run in bubbling phase. .capture won’t prevent child handlers from running. They will still be run, but after the parent’s handler.

2 – I’ve fixed the @click event handler on the overlay div:

  • !displayOverlay doesn’t execute anything it just returns the negative boolean value of current displayOverlay value;
  • to assign false to displayOverlay you’d need: @click="() => { displayOverlay = false }". Vue allows us to write a shorter version: @click="displayOverlay = false" (will auto wrap it with an anonymous function).

3<div @click.stop>is short for <div @click="$event => $event.stopPropagation()">

Answered By – tao

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published