Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue combine event handlers

I have the following Vue event handlers with contenteditable:

<div contentEditable="true"
v-on:keyup="changed($event, current, 0)"
v-on:paste="changed($event, current, 0)"
v-on:blur="changed($event, current, 0)"
v-on:delete="changed($event, current, 0)"
v-on:focused="changed($event, current, 0)"></div>

However, I have many places where I call the same code and the code is getting long and verbose. Is there a way to combine event handlers? Something like:

v-on:keyup:paste:blur:delete:focused ?

like image 730
the_ Avatar asked Feb 19 '17 23:02

the_


2 Answers

You can create your custom directive for this purpose. This sample may help you:

Vue.directive('wrap-on', {
  bind: function(el, binding, vnode) {
    // Keep function to remove the event later.
    el.wrappedEventFunctions = el.wrappedEventFunctions || {};
    el.wrappedEventFunctions[binding.rawName] = binding.value;

    for (var key in binding.modifiers) {
      // Check if element is a vue component
      if (vnode.componentInstance) {
        vnode.componentInstance.$on(key, binding.value);
      } else {
        el.addEventListener(key, binding.value);
      }
    }
  },
  unbind: function(el, binding, vnode) {
    for (var key in binding.modifiers) {
      if (vnode.componentInstance) {
        vnode.componentInstance.$off(key, el.wrappedEventFunctions[binding.rawName]);
      } else {
        el.removeEventListener(key, el.wrappedEventFunctions[binding.rawName]);
      }
    }
  }
})

This directive will add event handlers to the element. It checks if the element is a vue component; if it is a vue component it registers the events via $on. If it is not a vue component it uses addEventListener. You can change this behavior if you want.

And usage is like:

<input v-wrap-on.click.keydown="mixedCallback" />

Or:

<some-custom-component v-wrap-on.click.keydown="mixedCallback">
    ...
</some-custom-component>
like image 191
Yves Avatar answered Sep 28 '22 02:09

Yves


I don't think that there is a way, currently, to combine event listeners like you're describing.

What you could do is make this div it's own wrapper component (named 'editable-wrapper', for example) and emit one change event:

<div
  contentEditable="true"
  v-on:keyup="$emit('change', {$event, current} )"
  v-on:paste="$emit('change', {$event, current} )"
  v-on:blur="$emit('change', {$event, current} )"
  v-on:delete="$emit('change', {$event, current} )"
  v-on:focused="$emit('change', {$event, current} )">
</div>

And then you would only need to listen to one change event on the component (data is an object with $event, and current properties):

<editable-wrapper @change="changed(data)"></editable-wrapper>
like image 30
thanksd Avatar answered Sep 28 '22 03:09

thanksd