Vue.js Components - Custom Events

Parent components use props to pass data to child components, but if a child component needs to pass data back, custom events are required!

We can use v-on to bind custom events. Each Vue instance implements the events interface (Events interface), that is:

  • Use$on(eventName)Listen for events
  • Use$emit(eventName)Trigger events

In addition, the parent component can use v-on directly where the child component is used to listen for events triggered by the child component.

In the following example, the child component is completely decoupled from its outside. All it does is trigger an internal event that the parent component cares about.

Example

<div id="app"> <div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> </div> <script> Vue.component('button-counter', { template: '<button v-on:click="incrementHandler">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementHandler: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } }) </script>

Try it »

If you want to listen to a native event on the root element of a component, you can use the .native modifier on v-on. For example:

<my-component v-on:click.native="doTheThing"></my-component>

data must be a function

In the above example, you can see that the data in the button-counter component is not an object, but a function:

data: function () {
  return {
    count: 0
  }
}

The benefit is that each instance can maintain an independent copy of the returned object. If data is an object, it will affect other instances, as shown below:

Example

<div id="components-demo3" class="demo"> <button-counter2></button-counter2> <button-counter2></button-counter2> <button-counter2></button-counter2> </div> <script>var buttonCounter2Data = { count: 0 } Vue.component('button-counter2', { /* data: function () { // data option is a function, components do not affect each other return { count: 0 } }, */ data: function () { // data option is an object, will affect other instances return buttonCounter2Data }, template: '<button v-on:click="count++">Clicked {{ count }} times.</button>' }) new Vue({ el: '#components-demo3' }) </script>

Try it »

v-model for Custom Components

By default, v-model on a component uses the prop named value and the event named input.

<input v-model="parentData">

Equivalent to:

<input 
    :value="parentData"
    @input="parentData = $event.target.value"
>

In the following example, the custom component example-input is defined. The initial value of num in the parent component is 100. Changing the value in the child component can update the parent component's num in real time:

Example

<div id="app"> <example-input v-model="num"></example-input> <p>The entered number is: {{num}}</p> </div> <script> Vue.component('example-input', { template: ` <p> <!--Contains the event named input--> <input ref="input" :value="value" @input="$emit('input', $event.target.value)" > </p>`, props: ['value'], // prop named value }) new Vue({ el: '#app', data: { num: 100, } })</script>

Try it »

Because v-model passes value by default, not checked, for checkbox or radio button components, we need to use the model option. The model option can specify the current event type and the props passed in.

Example

<div id="app"> <base-checkbox v-model="lovingVue"></base-checkbox> <div v-show="lovingVue">If the checkbox is checked, I will be displayed.</div> </div> <script>// Register Vue.component('base-checkbox', { model: { prop: 'checked', event: 'change' // onchange event }, props: { checked: Boolean }, template: `<input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change', $event.target.checked)" >` }) // Create root instance new Vue({ el: '#app', data: { lovingVue: true } })</script>

Try it »

In the example, the value of lovingVue is passed to the checked prop, and when <base-checkbox> triggers the change event, the value of lovingVue is also updated.

Other Extensions