简体   繁体   中英

Is there a way to use dynamic event modifiers in VueJS?

I'm creating a button component in VueJS. I've made a dynamic event with a prop, plus event function and params as props as well. That works fine, the parent can set whatever event to trigger a method. However I want to be able to set modifiers on that event as well but don't see a way to do that. Is it possible?

The button component:

<button class="btn" :class="[styles, cssClasses]" role="button"
    @[event]="onEvent(eventParams)" 
    :disabled="disabled">
    <slot></slot>
</button>

The parent:

<Button 
    :event="'click'" 
    :onEvent="logEvent" 
    :eventParams="'This is a test message'">Test button</Button>

Adding a static modifier to the dynamic event works @[event].prevent=... but I want to be able to set the modifier from a prop, or not have it at all.

I also tried setting up an event listeners object but can't see a way to add modifiers to those either. At least in this option I can pass the event and preventdefault the old fashioned way, like our grandparents did.

moveAllListeners() {
    const me = this
    return Object.assign({},
        this.$listeners,
        {
            click(e) {
                e.preventDefault()
                me.moveAll()
            },
            mouseenter(e) {
                console.log('Mouse entered');
            }
        }
    )
}

Event modifiers cannot be dynamic because they are applied at "compile time" (when the template is compiled).

You'll have to implement this all manually; how you do it exactly is up to you, but it could be something like this:

<button @[event]="onEvent">
props: [
  'event',
  'eventParams',
  'eventPrevent', 
],

methods: {
  onEvent(e) {
    if (this.eventPrevent) {
      e.preventDefault()
    }

    // Use this.eventParams here...
  }
}

I'm not sure what your requirements are, but it seems like this is a bad approach from the start. Why does a custom Button component need this kind of behavior? Why do you need Button to operate like this?

I am not quite sure why you would need to operate such magic. Can you provide a bit more informations about your requirements please?

Why can't you just do like this:

<button
    class="btn"
    :class="[styles, cssClasses]"
    role="button"
    :disabled="disabled"
    v-on="$listeners"
>
    <slot></slot>
</button>
<Button @click="logEvent('This is a test message')">
    Test button
</Button>

The only reason I can imagine that would require to have these in a prop, would be because of some dynamic actions set up.

But you could have something like this in your parent component:

<template>
    <Button
        v-for="(button, i) in dynamicButtons"
        :key="`button_${i}`"
        @[button.event]="button.action"
    >
        Test button
    </Button>
</template>

<script>
    export default {
        name: 'Sandbox',
        
        data () {
            dynamicButtons: [
                {
                    content: 'Test button 1',
                    event: 'click',
                    action:  () => logEvent('Click w/o prevention')
                },
                {
                    content: 'Test button 2',
                    event: 'click',
                    action:  (e) => {
                        e.preventDefault()

                        logEvent('Click with prevention')
                    }
                },
                {
                    content: 'Test button 3'
                    event: 'mouseenter',
                    action: logEvent('Mouse entered')
                }
            ]
        },

        /* ... */
    }
</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM