Hao Wu
Hao Wu

Reputation: 20920

How do I use v-on="$listeners" except for @click?

I have a Button.vue looks like this. I'm using v-on="$listeners" to pass all listeners to <a>.

<template>
    <a
        v-bind="$attrs"
        v-on="$listeners"
        class="Button"
        href="javascript: void(0)"
        :class="{ disabled }"
        @click="onClick()"
    >
        <slot></slot>
    </a>
</template>

<script>
    export default {
        props: {
            disabled: {
                type: Boolean,
                default: false
            }
        },
        methods: {
            onClick() {
                if (!this.disabled) {
                    this.$emit('click');
                }
            }
        },
    };
</script>

But I need a custom check before propagating the @click event, so I also defined @click. But when I define both v-on="$listeners" and @click="onClick()" at the same time, the onClickDelete function get called twice. I also tried @click.prevent, but still doesn't work.

<Button @click="onClickDelete">Delete</Button>

Is there a way I can define v-on="$listeners" for all the events except @click?

Here's the code sandbox.

Upvotes: 6

Views: 12688

Answers (1)

tony19
tony19

Reputation: 138696

You could create a copy of $listeners (by spreading it into a new object), and overwrite click:

<a v-on="{ ...$listeners, click: () => {} }">

demo 1

Or create a computed prop that excludes any click event handler:

export default {
  computed: {
    myListeners() {
      const { click, ...listeners } = this.$listeners // exclude `click`-listener
      return listeners
    },
  },
}

Then bind that prop to v-on in place of $listeners:

<a v-on="myListeners">

demo 2

Upvotes: 24

Related Questions