Bind Multiple Events To V-on Directive In Vue
Solution 1:
1. With Event Modifiers
If you are relying on event
s, 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()
ontouchmove
rather thantouchstart
. 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"