Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does v-on="..." syntax mean in VueJS?

I came across a Vuetify example for the v-dialog component which has the scoped slot called activator defined as follows:

  <template v-slot:activator="{ on }">
    <v-btn
      color="red lighten-2"
      dark
      v-on="on"
    >
      Click Me
    </v-btn>
  </template>

I understand the purpose of scoped slots from VueJS docs and the concept of destructuring slot props but I don't understand what the meaning of v-on="on" is in this example. In particular what it means when the event is not specified with the v-on directive?

The VueJS docs on v-on only show its usage in combination with an event name explicitly specified (eg. v-on:click="...") but there is no explanation of just using it as v-on="...".

Can someone explain this syntax and its usage in the Vuetify example?

like image 707
mlst Avatar asked Aug 16 '19 11:08

mlst


People also ask

What is V-on in Vue?

The v-on:click directive is a Vue. js directive used to add a click event listener to an element. First, we will create a div element with id as app and let's apply the v-on:click directive to a element. Further, we can execute a function when click even occurs. Syntax: v-on:click="function"

What is a V-model in Vue?

Vue v-model is a directive that creates a two-way data binding between a value in our template and a value in our data properties. A common use case for using v-model is when designing forms and inputs. We can use it to have our DOM input elements be able to modify the data in our Vue instance.

What is V once in Vuejs?

If you – for whatever reason – want to only output something one time, then you can use the v-once directive. This directive ensures that an element is only rendered once, and when Vue. js re-renders the page, the element and all of its children will be considered as static content and thereby skipped.

What is V-bind and V-on?

v-bind is a one-way binding. v-model is used for binding form elements like inputs, radio buttons, textarea, checkboxes. It is used for binding data, attributes, expressions, class, styles. V-model is input value sensitive. It is also used to pass props to child components.


1 Answers

TLDR:

basic usage

<!-- object syntax (2.4.0+) --> 
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>]

So basically @click="..." equals v-on:click="..." equals v-on="{click:...}"


TLDR:

vuetify implementation:

genActivator () {
      const node = getSlot(this, 'activator', Object.assign(this.getValueProxy(), {
        on: this.genActivatorListeners(),
        attrs: this.genActivatorAttributes(),
      })) || []

      this.activatorNode = node

      return node
    }

Some insight:


It is useful if you want to abstract components and pass down multiple listeners at once instead of writing multiple lines of assignments.


Consider a component:

export default {

  data() {
    return {
      on: {
        click: console.log,
        contextmenu: console.log
      },
      value: "any key value pair"
    }
  }
}
<template>
  <div>
    <slot name="activator" :on="on" :otherSlotPropName="value" >
      <defaultComponent v-on="on" />
    </slot>
  </div>
</template>

Given the component above, you can access the slot properties and pass them into your custom component:

<ExampleComponent>
  <template v-slot:activator="{ on, otherSlotPropName }">
    <v-btn
      color="red lighten-2"
      dark
      v-on="on"
    >
      Click Me
    </v-btn>
  </template>
 <ExampleComponent />

Somethimes its easier to see it in plain javascript:

Comparing the component from above - with render function instead of template:

export default {

  data() {
    return {
      on: {
        click: console.log,
        contextmenu: console.log
      },
      value: "any key value pair"
    }
  },
  render(h){

    return h('div', [
      this.$scopedSlots.activator &&
      this.$scopedSlots.activator({
        on: this.on,
        otherSlotPropName: this.value
      })
      || h('defaultComponent', {
        listeners: this.on
      }
    ]
  }
}

In the source:

In case of a blank v-on="eventsObject" the method bindObjectListener will be called resulting in the assignment of the events to data.on.

This happens in the createComponent scope.

Finaly the listeners are passed as VNodeComponentOptions and updated by updateListeners.


Where Vue extends - the Vuetify implementation inspected:

When taking into account that one can join and extend vue instances, one can convince himself that any component can be reduced to a more atomic version.

This is what vuetify utilizes in the e.g. v-dialog component by creating a activator mixin.

For now one can trace down the content of on mounted by the activatable:

const simplyfiedActivable = {

  mounted(){
    this.activatorElement = this.getActivator()
  },
  watch{
    activatorElement(){
      // if is el?
      this.addActivatorEvents()
    }
  },
  methods: {
    addActivatorEvents(){
      this.listeners = this.genActivatorListeners()
    },
    genActivatorListeners(){
      return {
        click: ...,
        mouseenter: ...,
        mouseleave: ...,
      }
    },
genActivator () {
      const node = getSlot(this, 'activator', Object.assign(this.getValueProxy(), {
        on: this.genActivatorListeners(),
        attrs: this.genActivatorAttributes(),
      })) || []

      this.activatorNode = node

      return node
    },
  }
}

With above snippet all there is left is to implement this into the actual component:

// vuetify usage/implemention of mixins 
const baseMixins = mixins(
  Activatable,
  ...other
)

const sympliefiedDialog = baseMixins.extend({
  ...options,
  render(h){
    
    const children = []
    children.push(this.genActivator())
    return h(root, ...options, children)
  }
})

like image 200
Estradiaz Avatar answered Oct 28 '22 15:10

Estradiaz