Yes! What you're looking for is $emit()
, in combination with the v-on
directive, both of which it sounds like you're already using.
In the child component that you mention, the lowest one on the chain, you're already capturing a click
event from some component, and then presumably using $emit('my-event', [...some data...])
to emit a new event out from the child component itself.
All you need to do now is to add event listeners and handlers in the components up the chain, using Vue's custom events mechanic, so that they can receive and emit their own events, and the data can make it up to the parent. Custom events allow your components to emit and listen for events of any name, which may carry any data they'd like (this means they're not limited to being click
/ hover
/ blur
/ etc.).
Here's the step-by-step of that approach:
(Structure: Parent <--> Child #1 <--> Child #2 <--> Child #3
)
- Child #3 captures a
click
event, and emits an event in its handler
- Child #2 is listening for this event on #3, captures it, and
$emit
s its own event in its handler
- Child #1 is listening for this event on #2, captures it, and emits own event in its handler
- Parent captures event, and executes handler
In code, you'll have a listener and handler in each of your components, which can look something like this:
(I've used inline handlers here for brevity, but you can use defined methods as handlers too, just call this.$emit(...)
from the method.)
Child #3:
<component ... @click="$emit('my-event-a', $event)" />
Child #2:
<ChildComponent3 ... @my-event-a="$emit('my-event-b', $event)" />
Child #1:
<ChildComponent2 ... @my-event-b="$emit('my-event-c', $event)" />
Parent:
<ChildComponent1 ... @my-event-c="myHandler" />
$event
here is just special Vue syntax for referencing the event data in an inline handler, which in this case allows your new event to contain the same data.
The events in the various child components can be named whatever you'd like, just make sure that the respective listeners are listening for the correct event name (eg. @event-x="..."
for $emit('event-x')
and @pizza-eaten="..."
for $emit('pizza-eaten')
).
I also wanted to mention that passing the event
object (or any data at all) with an emitted event is completely optional. To do so, just invoke $emit
with the event name and no other arguments: $emit('my-event')
. This is useful when you simply care that an event has occurred, and the handler requires no further info.
There are many ways to approach this problem, but this is the most straightforward to understand, and works great as long as you don't need tons of direct interaction between a component and its deeply nested children.
If you do find your component structure getting more complicated, then you may want to look into a fully realized state management solution, like Vuex, which allows your components to interact with a state manager rather than having to deal with tons of events through a complicated component structure.