问题
I came across an Vuetify example for 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 is the meaning of v-on="on"
in this example. In particular what it means when event is not specified with v-on
directive?
The VueJS docs on v-on only shows its usage in combination with 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?
回答1:
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)
}
})
来源:https://stackoverflow.com/questions/57524110/what-does-v-on-syntax-mean-in-vuejs