83
<div id="largeArea" v-on:click="do_X">
    <button>Button</button>
</div>

So I have this issue in Vue where I don't want do_X to trigger when I click on the button, although its a part of the largeArea.

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
eozzy
  • 66,048
  • 104
  • 272
  • 428

5 Answers5

135

I found that using the 'stop' event modifier on the child element worked for me. eg

<div id="app">
  <div id="largeArea" @click="do_X">
    <button @click.stop="do_Y">Button</button>
  </div>
</div>
omarjebari
  • 4,861
  • 3
  • 34
  • 32
  • 8
    This is a much better answer as in my case I need to be able to click anywhere on the larger div to perform a specific action, and on clicking on the small element to perform another action. In my case "v-on:click.stop="doSomeAction()" worked. – Meanman Mar 04 '19 at 15:53
  • 4
    @Meanman there's little difference between `stop` on the child and `self` on the parent for isolating the event source. However, the former has a side-effect of preventing the event from reaching lower levels in the document. For example, you could not track all clicks on the `document` or `body` if you use `stop` – Phil Apr 02 '19 at 00:18
  • Great, this even worked with a nested `` and without event handler for me: `` – Gnietschow Oct 20 '20 at 08:10
70

From the documentation, use the self event modifier to only capture events originating on the element itself.

<div id="largeArea" v-on:click.self="do_X">

new Vue({
  el: '#app',
  methods: {
    do_X () {
      console.log(Date.now(), 'do_X')
    }
  }
})
#largeArea {
  padding: 20px;
  border: 1px solid black;
}
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13/dist/vue.js"></script>
<div id="app">
  <div id="largeArea" @click.self="do_X">
    <button>Button</button>
  </div>
</div>
tony19
  • 125,647
  • 18
  • 229
  • 307
Phil
  • 157,677
  • 23
  • 242
  • 245
  • 15
    is there an event decorator I can add to the child element. because I do want event bubbling for every child element except this one other button. {{UPDATE: i used @click.prevent.stop for desired effect! }} – Akin Hwan Jun 07 '18 at 20:12
12

Prevent bubbling for all clicks inside a container <div>

<div @click.stop="" class="action">

  <button @click="someClickAction1()">Action 1</button>

  <button @click="someClickAction2()">Action 2</button>

<div>

Prevent bubbling on an existing click action

<button @click.stop="someClickAction()">Single Action</button>
Rameez Rami
  • 5,322
  • 2
  • 29
  • 36
4

Neither of the provided answers. In my situation it's wrapped in a <router-link> not a <div>.

I called e.preventDefault() on the child element and it worked

<router-link>
    <div @click="do_X"></div>
</router-link>

new Vue({
  el: '#app',
  methods: {
    do_X (e) {
    e.preventDefault();
      console.log(Date.now(), 'do_X')
    }
  }
})
Ian
  • 3,539
  • 4
  • 27
  • 48
2

I was creating a navigation bar and had similar requirements. I want the popup menu to be closed when clicked anywhere accept the menu or its children.

This can be done by using event modifiers. Fore reference see this docs

Specifically, we can use stop event modifier.

<div id="largeArea" v-on:click="do_X()">
    <button @click.stop="">Button</button>
</div>

.stop will stop the event propagation.


In my case better solution was to use e.target != this.$el

mounted() {
    window.addEventListener('click', (e)=>{
        if(e.target !== this.$el)
            this.showChild = false;
    })
}
Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122