Skip to content Skip to sidebar Skip to footer

Bind Multiple Events To V-on Directive In Vue

In jQuery you can bind multiple events by doing something like this: $('#myDiv').on('touchstart mousedown', // more code here And as far as I understand this will listen for touchs

Solution 1:

1. With Event Modifiers

If you are relying on events, you could try binding with event modifiers and sort of chain them inline. Something like:

<a @click.stop="doThis" @click.right="showContextMenu"></a>

2. Attaching events programmatically

Or, you could create your list of events and their respective implementations to attach with and do the loop with v-on, a workaround from this post:

created() {
    constEVENTS = [
      {name: 'my-event1', callback: () =>console.log('event1')},
      {name: 'my-event2', callback: () =>console.log('event2')},
      {name: 'my-event3', callback: () =>console.log('event3')}
    ]

    for (let e ofEVENTS) {
      this.$on(e.name, e.callback); // Add event listeners
    }
  }

<button @click="$emit('my-event1')">Raise event1</button>
<button @click="$emit('my-event2')">Raise event2</button><button @click="$emit('my-event3')">Raise event3</button>

3. v-on multiple values

Otherwise, just like you can do v-bind on multiple values, you can actually do the same with v-on for events.

<div id="mydDiv" v-on="handlers"></div>

// ...data() {
  const vm = this;

  return {
    handlers: {
      mousedown: vm.divMousedown,
      touchstart: vm.divTouchstart
    }
  }
},

methods: {
  divMousedown() {
    console.log('event: mousedown');
  },
  divTouchstart() {
    console.log('event: touched');
  }
}

If you need to break down the handlers by type of event, try examining the type while the event is being fired, so in your case, since touchstart seems to also trigger mousedown, perhaps:

methods: {
  onTouched(evt) {
    evt.preventDefault();

    if (evt.type === 'mousedown') {
        // handle mousedown
    }
    else if (evt.type === 'touchstart') {
        // ...
    }
  }
}

Note: You might want to call preventDefault() on touchmove rather than touchstart. That way, mouse events can still fire and things like links will continue to work.

Solution 2:

No you are not missing anything obvious. "touchstart mousedown" is a short-hand notation provided by jQuery for convenience. Vue does not provide a similar convenience (probably because the event binding syntax for attrs can already get pretty hairy with all the provided options).

The correct method would be as you stated, using two separate attributes: @touchstart="doSomething()" or @mousedown="doSomething()"

Solution 3:

Binding to multiple events is not supported by vue on purpose because of inherent limitations in attribute names and the desire to avoid runtime overhead.

If you absolutely must have multi-event bindings, a custom directive would be the way to go.

(The following code is shamelessly copied from the linked JSFiddle because SO has disallowed linking to fiddles without code in the answer)

functionfunctionWrapper(e) {
  /* add filters to handle event type before propagating to callback function for custom event handler */
  e.target.__handler__.fn(e)
}

Vue.directive('multiEvent', {
  bind: function(el, binding, vnode) {
    el.__handler__ = binding.value
    binding.value.evt.forEach(e => el.addEventListener(e, functionWrapper))
  },
  unbind: function(el, binding) {
    el.__handler__.evt.forEach(e => el.removeEventListener(e, functionWrapper))
    el.__handler__ = null
  }
})

Usage:

<input v-multi-event="{ evt: ['click', 'blur', 'change', 'keydown'], fn: someCallback }">

Post a Comment for "Bind Multiple Events To V-on Directive In Vue"