pure_bordem
pure_bordem

Reputation: 159

VueJS - Conditional component mouse events

New to Vue and frameworks in general, and may have my thinking not very "Vue-like".

Trying to make a "super" button component that takes a prop, which dictates the buttons behavior so I only have to maintain one button component. The ideal form when implementing would like something like this...

<super-button isType="string"></super-button>

The template is...

    <button class="buttonLow" v-bind:class="{buttonHigh: isSelected}">
            <slot></slot>
    </button>

Where isType prop could be momentary momentary-multi toggle or toggle-multi.

I have a basic set of event emitters/methods and listeners that work regardless of the isType and simply makes the buttons state high or low / on or off using another prop isSelected.

The problem is trying to conditionally setup the mouse events depending on the isType. While figuring out the logic, I used the @ syntax to setup the mouse events @click @mousedown @mouseup etc. and everything worked great by itself. For example, the events for a momentary button during testing looked like this...

<button @mousedown="emitButtonHigh()" @mouseup="emitButtonLow" @mouseleave="emitButonLow"></button>

However, a simple toggle button looked more like this...

<button @click="emitButtonToggle()"></button>

Obviously there is a bit of conflict there.

My attempted work around was to use a switch statement in created() that would take isType as the expression and conditionally register the appropriate mouse events...

created(){
    switch(this.isType){
        case ("momentary"):{
            //attach on events
            break;
        }
        case ("toggle"):{
            //attach on events
            break;
        }
        case ("toggle-multi"):{
            //attach on events
            break;
        }
        default:{
            break;
        }
    }
}

While switch itself is working, I can't figure out how to attach the mouse events in this context. I can attach a custom event no problem using...

    this.$root.$on('my-custom-event', ()=>{
        //do stuff
    });

but trying do something like...

    this.$root.$on('click', ()=>{
        //do stuff
    });

or...

    this.$on('click', ()=>{
        //do stuff
    });

Does not work, nor can I figure out any way to write it out that creates the same functionality as @click let alone @mousedown @mouseup or other built-in events.

TL;DR

How do you write out the @ syntax or v-on syntax, for built-in events (click, mousedown, mouseup, etc.), using $on syntax, so the events actually fire?

Upvotes: 3

Views: 4918

Answers (1)

Yom T.
Yom T.

Reputation: 9200

You could attach all these component events on a single handler, determine the event.types as they're fired and emit your custom events from here, while optionally passing additional arguments.

const SuperButton = Vue.extend({
  template: `
    <button 
      @mousedown="emitCustomEvent" 
      @mouseup="emitCustomEvent" 
      @mouseleave="emitCustomEvent">
      <slot></slot>
    </button>
  `, 

  props: {
    isType: {
      type: String,
      default:
        String
      },
      
    // ...
  },

  methods: {
    emitCustomEvent(e) {
      let type = e.type.substr('mouse'.length);
      let args = {
        type,
        isSelected: type === 'down',
        args: {
          // Your additional args here
        }
      };
      
      switch(this.isType) {
        case ("momentary"):{
          //attach on events
          break;
        }
          // ...
      }
      
      // Or emit events regardless of the "isType"
      
      this.$emit(`mouse:${type}`, args);
      this.$emit('mouse', args);
    }
  }
});

new Vue({
  el: '#app',

  methods: {
    mousing(args) {
      console.log(`mouse:${args.type} from component.`);
    },
    
    mouseLeaving() {
      console.log('Mouse leaving.');
    }
  },

  components: {
    SuperButton
  }
});

Vue.config.devtools = false;
Vue.config.productionTip = false;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <super-button @mouse="mousing">Super button</super-button>
  
  <super-button @mouse:leave="mouseLeaving">Super button 2, detecting leaving only</super-button>
</div>

Upvotes: 1

Related Questions