Meaning of v-slot:activator="{ on }"

vue.jsVuejs2vuetify.js

vue.js Problem Overview


Looking at the Vuetify example code for v-toolbar, what is the purpose of v-slot:activator="{ on }"? For example:

<template v-slot:activator="{ on }">
  <v-toolbar-title v-on="on">
    <span>All</span>
    <v-icon dark>arrow_drop_down</v-icon>
  </v-toolbar-title>
</template>

<script>
  export default {
    data: () => ({
      items: [
        'All', 'Family', 'Friends', 'Coworkers'
      ]
    })
  }
</script>

As far as I can see, on is not a defined variable anywhere, so I don't see how this is working. When I try it in my project, Internet Explorer throws an error on the <template v-slot:activator="{ on }">, but if I remove it, the page renders.

vue.js Solutions


Solution 1 - vue.js

You're likely referring to this example:

<v-toolbar color="grey darken-1" dark>
  <v-menu :nudge-width="100">
    <template v-slot:activator="{ on }">
      <v-toolbar-title v-on="on">
        <span>All</span>
        <v-icon dark>arrow_drop_down</v-icon>
      </v-toolbar-title>
    </template>

    ...
  </v-menu>
</v-toolbar>

The following line declares a scoped slot named activator, and it is provided a scope object (from VMenu), which contains a property named on:

<template v-slot:activator="{ on }">

This uses destructuring syntax on the scope object, which IE does not support.

For IE, you'd have to dereference on from the scope object itself:

<template v-slot:activator="scope">
  <v-toolbar-title v-on="scope.on">

But the ideal solution IMO is to use a Vue CLI generated project, which includes a Babel preset (@vue/babel-preset-app) to automatically include the transforms/polyfills needed for the target browsers. In this case, babel-plugin-transform-es2015-destructuring would be automatically applied during the build.

Details on the activator slot

VMenu allows users to specify a slotted template named activator, containing component(s) that activate/open the menu upon certain events (e.g., click). VMenu provides listeners for those events via an object, passed to the activator slot:

<v-menu>
  <template v-slot:activator="scopeDataFromVMenu">
    <!-- slot content goes here -->
  </template>
</v-menu>

The slot content can access VMenu's event listeners like this:

<v-menu>
  <template v-slot:activator="scopeDataFromVMenu">
    <button v-on="scopeDataFromVMenu.on">Click</button>
  </template>
</v-menu>

For improved readability, the scoped data can also be destructured in the template:

<!-- equivalent to above -->
<v-menu>
  <template v-slot:activator="{ on }">
    <button v-on="on">Click</button>
  </template>
</v-menu>

The listeners from the scope object are passed to the <button> with v-on's object syntax, which binds one or more event/listener pairs to the element. For this value of on:

{
  click: activatorClickHandler // activatorClickHandler is an internal VMenu mixin
}

...the button's click handler is bound to a VMenu method.

Solution 2 - vue.js

I think the original question is about understanding the "on" object. It is best explained here:

https://github.com/vuetifyjs/vuetify/issues/6866

Essentially "on" is a prop passed in from the activator. What v-on="on" does is bind that on prop to the component. "on" itself is all of the event listeners passed from the activator.

Solution 3 - vue.js

To call out a readability tip, it's possible to use this syntax:

<v-menu>
    <template v-slot:activator="{ on: activationEvents }">
        <v-btn v-on="activationEvents">
            I like turtles 🐢
        </v-btn>
    </template>
</v-menu>

In my brain this has a more fluent readability than v-on="on", which to me is like observing a conversation consisting solely of:

  • Person 1: "Hey"
  • Person 2: "Yep"

Understand? ;)

By the way, activationEvents could be any alias, like "slotEvents", "listeners", "anyOldEvent", or whatever makes more sense to the reader as a renaming of the mysterious on.

Solution 4 - vue.js

Run the below code,you will know what is 'attrs' an 'on' in v-menu.

<v-menu>
    <template v-slot:activator="{ on, attrs }">
        <div v-bind="attrs" v-on="on">
            v-menu slot activator:
            <br />
            attrs == {{ JSON.stringify(attrs) }}
            <br />
            on == {{ '{' + Object.keys(on).map(k => k + " : " + on[k]).join(',') + '}' }}
        </div>
    </template>
</v-menu>

Result:

v-menu slot activator:
attrs == {"role":"button","aria-haspopup":true,"aria-expanded":"false"}
on == {
click:function (e) {if (_this.openOnClick) {onClick && onClick(e);}_this.absoluteX = e.clientX;_this.absoluteY = e.clientY;},
keydown:function () { [native code] }
}

Explanation:

<div v-bind="attrs" v-on="on"> equals

<div 
    v-bind="{role:'button',aria-haspopup:true,aria-expanded:'false'}" 
	v-on="{click:function (e) {/*implement by v-menu*/},keydown:function () {/*implement by v-menu*/}}"
>

Starting in vue 2.4.0+, v-on also supports binding to an object of event/listener pairs without an argument. Note when using the object syntax, it does not support any modifiers. Example:

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

About <template> tags in Internet Explorer throws an error :

as vuetify docs say:

Template caveat

Due to Internet Explorer’s limited support for <template> tags, you must send fully compiled dom elements to the browser. This can be done by either building your Vue code in advance or by creating helper components to replace the dom elements. For instance, if sent directly to IE, this will fail:

<!-- Vue Component -->
<template v-slot:items="props">
  <td>{‌{ props.item.name }‌}</td>
</template>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionArawView Question on Stackoverflow
Solution 1 - vue.jstony19View Answer on Stackoverflow
Solution 2 - vue.jsPropertyWebBuilderView Answer on Stackoverflow
Solution 3 - vue.jsNoah StahlView Answer on Stackoverflow
Solution 4 - vue.jsHaoQiRenView Answer on Stackoverflow