Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using custom components triggers the click event twice #813

Closed
LastHeaven opened this issue Mar 11, 2020 · 14 comments
Closed

Using custom components triggers the click event twice #813

LastHeaven opened this issue Mar 11, 2020 · 14 comments

Comments

@LastHeaven
Copy link

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

@LastHeaven
Copy link
Author

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

@LastHeaven LastHeaven changed the title 使用自定义组件会触发两次click事件 Using custom components triggers the click event twice Mar 11, 2020
@underfin
Copy link
Member

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

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

@LastHeaven
Copy link
Author

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

@LastHeaven
Copy link
Author

And version 3.0.0-alpha.7 is fine.

@LastHeaven
Copy link
Author

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>

@hareku
Copy link
Contributor

hareku commented Mar 11, 2020

@LastHeaven
The attr fallthrough behavior was changed at e1660f4 for vuejs/rfcs#137.
When you set inheritAttrs: false to MButton component, it will work as you expected.

@LastHeaven
Copy link
Author

@hareku
Thanks,it worked。

@yyx990803
Copy link
Member

yyx990803 commented Mar 11, 2020

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)

@SomeoneIsWorking
Copy link

SomeoneIsWorking commented Dec 3, 2021

@LastHeaven The attr fallthrough behavior was changed at e1660f4 for vuejs/rfcs#137. When you set inheritAttrs: false to MButton component, it will work as you expected.

Yes but this breaks both v-text and class and probably many others too

You can simply remove your click listener in the child

But the child triggers click.prevent
With this I have to add .prevent to everywhere now

@Chrisx0385
Copy link

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)

That is quite unexpected behavior. When I define a custom event with the same name as a native event (but with a different payload) I would expect it to override the native one. Having both is from my opinion never what is wanted.

@mkidsc1603
Copy link

This issue should be took a look again.
Now , It is like tol must define specific props & event (include common e.g. class、style、click ...)
Generally, some strange situation occured when I encapsulate other UI Framework component 😢

@SomeoneIsWorking
Copy link

I'm changing my statement on this issue. There is no problem regarding the behavior. If you want to omit specific events you can use inheritAttrs: false combined with v-bind="omit($attrs, 'onClick') for example (omit is a lodash function here)
People struggling with it most likely don't know what they are doing like I was before.
Needs to be said Vue 3 isn't just a version change, it's a different framework.

@occamz
Copy link

occamz commented Apr 11, 2022

Worked for me to declare the event with emits.

export default {
  name: "SomeComponent",
  emits: ["click"],
  ...
}

1VinceP added a commit to 1VinceP/vue-material-design-icons that referenced this issue Apr 15, 2022
In Vue 3, click events fall through meaning each event is fired twice when adding @click prop to the component. Adding `emits: ['click']` tells the component to expect an external click event, therefore preventing the double event. See [here](vuejs/core#813) for more details
@ronssij
Copy link

ronssij commented Jun 27, 2022

I am having the same issue for Vue2.
but mine is on v-on="$listeners" rendered on a functional component.

<template>
  <div class="aft-list-item" v-on="$listeners">
    <slot />
  </div>
</template>

<script>
export default {
  name: 'AftListItem',

  props: {
    noDivider: {
      type: Boolean,
      default: false
    }
  }
}
</script>

on my functional component.


return createElement('AftListItem', {
  on: {
    click: (event) => {
      this.handleClickedListItem(selection)
    }
  }
}, [
  has(this.$scopedSlots, 'item') ? _itemSlot(selection) : defaultItemContent(selection)
])

I have changed it to functional component. but im still having doublick on the click event.

<script>
export default {
  name: 'AftListItem',

  props: {
    noDivider: {
      type: Boolean,
      default: false
    }
  },

  render (createElement) {
    return createElement('div', {
      class: ['aft-list-item'],
      on: {
        click: (event) => {
          event.stopPropagation()

          console.log('testing')
        }
      }
    }, [this.$slots.default])
  }
}
</script>

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants