Vue-next: Using custom components triggers the click event twice

Created on 11 Mar 2020  ·  8Comments  ·  Source: vuejs/vue-next

Version

3.0.0-alpha.8

Reproduction link

none,不支持alpha版本的vue

Steps to reproduce

创建一个组件MButton

<template>
  <button @click="onClick"><slot/></button>
</template>

<script>

export default {
  name: 'MButton',
  setup (props, { emit }) {
    return {
      onClick () {
        emit('click')
      }
    }
  }
}
</script>

页面中使用

<template>
  <div>
    <img src="./logo.png">
    <h1>Hello Vue 3!</h1>
    <m-button @click="inc">Clicked {{ count }} times.</m-button>
  </div>
</template>

<script>
import { ref } from 'vue'
import MButton from './MButton'

export default {
  components: { MButton },
  setup (props, { emit }) {
    const count = ref(0)
    const inc = () => {
      count.value  
    }
    return {
      count,
      inc
    }
  }
}
</script>

<style scoped>
img {
  width: 200px;
}
h1 {
  font-family: Arial, Helvetica, sans-serif;
}
</style>

点击按钮

What is expected?

count从0变成1

What is actually happening?

count从0变成了2

Most helpful comment

In v3 all v-on listeners will fallthrough to child component root by default - which means it's no longer necessary to manually re-emit the click event. You can simply remove your click listener in the child instead of using inheritAttrs: false (which disables fallthrough for other attributes, e.g. class)

All 8 comments

Using custom components triggers the click event twice

Version

3.0.0-alpha.8

Reproduction link

none,not support

Steps to reproduce

Create a component named MButton

<template>
  <button @click="onClick"><slot/></button>
</template>

<script>

export default {
  name: 'MButton',
  setup (props, { emit }) {
    return {
      onClick () {
        emit('click')
      }
    }
  }
}
</script>

Use it in the page.

<template>
  <div>
    <img src="./logo.png">
    <h1>Hello Vue 3!</h1>
    <m-button @click="inc">Clicked {{ count }} times.</m-button>
  </div>
</template>

<script>
import { ref } from 'vue'
import MButton from './MButton'

export default {
  components: { MButton },
  setup (props, { emit }) {
    const count = ref(0)
    const inc = () => {
      count.value  
    }
    return {
      count,
      inc
    }
  }
}
</script>

<style scoped>
img {
  width: 200px;
}
h1 {
  font-family: Arial, Helvetica, sans-serif;
}
</style>

Click the button.

What is expected?

count from 0 change to 1

What is actually happening?

count from 0 change to 2

The click event trigger twice because the event is bubbling.
The code will works.

<button @click.stop="onClick"><slot/></button>

@underfin Is this a new feature?It's diffrence from vue2.

And version 3.0.0-alpha.7 is fine.

I tryed to use the .stop,but it seems not work。

<template>
  <button @click.stop="onClick"><slot/></button>
</template>

<script>

export default {
  name: 'MButton',
  setup (props, { emit }) {
    return {
      onClick () {
        emit('click')
      }
    }
  }
}
</script>

@LastHeaven
The attr fallthrough behavior was changed at https://github.com/vuejs/vue-next/commit/e1660f4338fbf4d2a434e13193a58e00f844379b for https://github.com/vuejs/rfcs/pull/137.
When you set inheritAttrs: false to MButton component, it will work as you expected.

@hareku
Thanks,it worked。

In v3 all v-on listeners will fallthrough to child component root by default - which means it's no longer necessary to manually re-emit the click event. You can simply remove your click listener in the child instead of using inheritAttrs: false (which disables fallthrough for other attributes, e.g. class)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cexbrayat picture cexbrayat  ·  4Comments

corkt picture corkt  ·  4Comments

NMFES picture NMFES  ·  3Comments

mannok picture mannok  ·  3Comments

doman412 picture doman412  ·  3Comments