Comunicar componentes en VueJS

Nuestras aplicaciones vuejs cuenta con infinidades de componentes con ciertas funcionalidades y en muchas ocasiones necesitamos que éstos tengan una comunicación entre ellos para que nuestra aplicación cuente con la funcionalidad que deseamos. En este articulo aprenderemos en pocos minutos una de las formas que existen para enviar información de un componente a otro con un ejemplo muy sencillo.

Creando los componentes que se comunicarán

Crearemos dos componentes llamados component1 y component2 en nuestra aplicación, mediante $emit enviaremos un evento con un nombre y una variable, con $on lo recibiremos en otro componente.

Comenzamos con el registro de los componentes en main.js:

import Vue from 'vue'
import App from './App.vue'
import Component1 from './components/Component1.vue'
import Component2 from './components/Component2.vue'

Vue.component('component1', Component1)
Vue.component('component2', Component2)

new Vue({
  el: '#app',
  render: h => h(App)
})

El componente component1 será un cuadrado con un background gris y añadiremos el evento $on que escuchará cuando se envie el evento changeColor para cambiar el background:

<template>
  <div :style="{ backgroundColor: color}" class="container">
    <h1>Component 1</h1>
  </div>
</template>

<script>
export default {
    name: 'component1',
    data: function(){
        return{
            color:'gray'
        }
    },
    created() {
        let me = this;
        /*Al crear el componente, declaramos una escucha en el evento changeColor, que se ejecutará si algún
        componente envia un evento con este nombre*/
        this.$root.$on('changecolor', (data)=>{
            me.color = data;
        });

    },
}
</script>

<style scoped>
    .container{
        display: inline-block;
        height: 300px;
        width: 300px;
    }
    h1{
        margin:0;
        line-height: 300px;
        color:white;
    }
</style>

El componente component2 tendrá 3 botones que ejecutará una función que enviará el evento del cambio de color mediante $emit:

<template>
   <div>
    <h1>Component 2</h1>
    <button @click="changeColor('red')" class="red">RED</button>
    <button @click="changeColor('blue')" class="blue">BLUE</button>
    <button @click="changeColor('green')" class="green">GREEN</button>
   </div>
</template>

<script>
export default {
    name: 'component2',

    methods: {
        //Al presionar el botón, emitiremos el evento changeColor y enviaremos el color seleccionado 
        changeColor(color){
            this.$root.$emit('changecolor', color);
        }
    },
}
</script>

<style scoped>
    button{
        padding:10px 25px;
        color:white;
        border-radius: 1rem;
        border:none;
        cursor:pointer;
    }
    .red{
         background-color:red;
    }
    .blue{
         background-color:blue;
    }
    .green{
         background-color:green;
    }
</style>

Una vez hecho esto, añadimos los componentes a la vista que queramos, en mi caso, en App.vue:

<template>
  <div id="app">
    <component1></component1>
    <component2></component2>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  margin-top: 60px;
}
</style>

Y este sería el resultado: