Meaning of v-slot:activator="{ on }"
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.
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.
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.
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
.