vue组件通信分为横向和纵向。

**纵向**

1. props 和 $emit

props:接收来自父组件的数据

$emit:触发事件

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body><div id="app"></div><script src="./node_modules/vue/dist/vue.js"></script><script>// 全局组件Vue.component('Parent', {data(){return {msg: 'I am the data of Parent!',childToParentData: 'I am the data of Parent!',};},template: `<div>                    <p> I am the parent component!</p>                    <Child :childData="msg" @childHandler="handerFn"/>                    <p>childToParentData: {{childToParentData}}</p>                </div>`,methods: {handerFn(val){console.log(val);this.childToParentData = val;},}})Vue.component('Child', {data(){return {msg: 'I am the data of Child!',inputVal: this.childData,};},props: ['childData'],template: `<div>                    <p> I am the child component!</p>                    <p>{{msg}}</p>                    <input v-model="inputVal" @input="changeVal(inputVal)" />                </div>`,methods: {changeVal(val){// 通过 $emit 触发,参数为 事件名,参数this.$emit('childHandler', val);}}})var App = {template: `<div>                    <Parent />                </div>`,};var vm = new Vue({el: '#app',data(){return {};},components: {App},methods: {},template: `            <App />            `})</script><pre>子组件向父组件传值1、自定义事件2、子组件原生事件3、原生事件的处理函数中通过$emit触发自定义事件注:子组件不能修改props中的值,否则报错,可通过子组件自己的数据接收props中的值来解决</pre></body></html>

2. $parent 和 $children

后代组件可以通过$parent.$parent.$parent这种形式跨级通信

父组件可以通过$children[0].$children[0]这种形式跨级通信,如果有多个子组件,索引不好控制

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body><div id="app"></div><script src="./node_modules/vue/dist/vue.js"></script><script>// 全局组件Vue.component('Parent', {data(){return {msg: 'I am the data of Parent!',grandToParent: '',};},template: `<div>                    <p> I am the parent component!</p>                    <input v-model="msg" @input="consoleFn"/>                     <p >{{grandToParent}}</p>                                         <hr />                    <Child/>                </div>`,methods: {consoleFn(){this.$children[0].parentMsg = this.msg;},},})Vue.component('Child', {data(){return {msg: 'I am the data of Child!',parentMsg: '',grandToChild: '',};},template: `<div>                    <p> I am the child component!</p>                    <p>{{msg}}</p>                    <button @click="consoleFn">attr</button>                     <p >{{parentMsg}}</p>                                       <p >{{grandToChild}}</p>                                       <hr />                    <GrandChild />                </div>`,methods: {consoleFn(){this.$children[0].childMsg = this.msg;},},})Vue.component('GrandChild', {data(){return {msg: 'I am the data of GrandChild!',childMsg: '',};},template: `<div>                    <p> I am the GrandChild component!</p>                    <p>{{msg}}</p>                    <button @click="consoleFn" >attr</button>                    <p >{{childMsg}}</p>                     <hr />                </div>`,methods: {consoleFn(){this.$parent.grandToChild = this.msg;this.$parent.$parent.grandToParent = this.msg;},},})var App = {template: `<div>                    <Parent />                </div>`,};var vm = new Vue({el: '#app',data(){return {};},components: {App},methods: {},template: `            <App />            `})</script><pre>$parent, $children, $root, $parent.$parent非响应式,如果有多个直接子组件</pre></body></html>

3. $attrs 和 $listeners

后代组件从$attrs获取父组件传给后代组件的数据

后代组件通过$emit触发$listeners的事件将数据传给父组件

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body><div id="app"></div><script src="./node_modules/vue/dist/vue.js"></script><script>// 全局组件Vue.component('Parent', {data(){return {msg: 'I am the data of Parent!',childToParentData: 'I am the data of Parent!',};},template: `<div>                    <p> I am the parent component!</p>                    <p>childToParentData: {{childToParentData}}</p>                    <button @click="consoleFn">attr</button>                    <br />                    <Child :parentMsg="msg" @childClick="parentHandler" v-bind="$attrs" v-on="$listeners"/>                </div>`,// inheritAttr: false,methods: {consoleFn(){console.log(this.$attrs);  // {}console.log(this.$listeners);  // {}},parentHandler(data){console.log(data);},},})Vue.component('Child', {data(){return {msg: 'I am the data of Child!',};},template: `<div>                    <p> I am the child component!</p>                    <p>{{msg}}</p>                    <button @click="consoleFn">attr</button>                                        <br />                    <GrandChild :childMsg="msg" @grandChildClick="childHandler" v-bind="$attrs" v-on="$listeners"/>                </div>`,// inheritAttr: false,methods: {consoleFn(){console.log(this.$attrs);  // {parentMsg: }console.log(this.$listeners);  //{childClick: }},childHandler(data){console.log(data);},},})Vue.component('GrandChild', {data(){return {msg: 'I am the data of GrandChild!',};},template: `<div>                    <p> I am the GrandChild component!</p>                    <p>{{msg}}</p>                    <button @click="consoleFn" >attr</button>                    <br />                </div>`,// inheritAttr: false,methods: {consoleFn(){console.log(this.$attrs);  // {parentMsg: , childMsg: }console.log(this.$listeners);   //{childClick: , grandChildClick: }this.$emit('childClick', this.msg);  // 如果不收集,$emit只能触发其父级的事件this.$emit('grandChildClick', this.msg); },},})var App = {template: `<div>                    <Parent />                </div>`,};var vm = new Vue({el: '#app',data(){return {};},components: {App},methods: {},template: `            <App />            `})</script><pre>1、$attrs收集属性2、$listeners收集事件</pre></body></html>

4. provide 和 inject

父组件向后代组件单向传递数据

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body><div id="app"></div><script src="./node_modules/vue/dist/vue.js"></script><script>// 全局组件Vue.component('Parent', {data(){return {msg: 'I am the data of Parent!',};},provide(){return {parentMsg: this.msg,};},template: `<div>                    <p> I am the parent component!</p>                    <input v-model="msg"/>  <!-- provide和inject绑定并不是可响应的, 所以msg的变化不会影响后代组件中已经接收到的msg的值 -->                    <button @click="consoleFn">attr</button>                    <hr />                    <Child/>                </div>`,methods: {consoleFn(){console.log(this);},},})Vue.component('Child', {data(){return {msg: 'I am the data of Child!',};},provide: {childMsg: 'I am the data of Child!',},inject: ['parentMsg'],template: `<div>                    <p> I am the child component!</p>                    <p>{{msg}}</p>                    <button @click="consoleFn">attr</button>                     <p >{{parentMsg}}</p>                                       <hr />                    <GrandChild />                </div>`,methods: {consoleFn(){console.log(this);},},})Vue.component('GrandChild', {data(){return {msg: 'I am the data of GrandChild!',};},inject: ['parentMsg', 'childMsg'],template: `<div>                    <p> I am the GrandChild component!</p>                    <p>{{msg}}</p>                    <button @click="consoleFn" >attr</button>                    <p >{{parentMsg}}</p>                     <p >{{childMsg}}</p>                     <hr />                </div>`,methods: {consoleFn(){console.log(this);},},})var App = {template: `<div>                    <Parent />                </div>`,};var vm = new Vue({el: '#app',data(){return {};},components: {App},methods: {},template: `            <App />            `})</script><pre>单向</pre></body></html>

**横向**

1. 数据总线 

用一个中间变量保存数据

var bus = new Vue() 

   $on绑定事件

   $emit触发事件

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body><div id="app"></div><script src="./node_modules/vue/dist/vue.js"></script><script>var bus = new Vue();// 全局组件Vue.component('Parent', {data(){return {msg: 'I am the data of Parent!',};},template: `<div>                    <p> I am the parent component!</p>                    <button @click="consoleFn">button</button>                    <br />                    <BrotherOne />                    <BrotherTwo />                </div>`,methods: {consoleFn(){console.log(bus);},},})Vue.component('BrotherOne', {data(){return {msg: 'I am the data of BrotherOne!',fromBrother: '',};},template: `<div>                    <p> I am the BrotherOne component!</p>                    <p>{{msg}}</p>                    <input v-model="fromBrother" @input="transformData"/>                                       <br />                </div>`,methods: {transformData(){bus.$emit('globalBus', this.fromBrother);},},})Vue.component('BrotherTwo', {data(){return {msg: 'I am the data of BrotherTwo!',fromBrother: '',};},template: `<div>                    <p> I am the BrotherTwo component!</p>                    <p>{{msg}}</p>                    <p>fromBrother: {{fromBrother}}</p>                    <button @click="consoleFn" >button</button>                    <br />                </div>`,methods: {consoleFn(){console.log(bus);},},mounted(){bus.$on('globalBus', val => {this.fromBrother = val;})}})var App = {template: `<div>                    <Parent />                </div>`,};var vm = new Vue({el: '#app',data(){return {};},components: {App},methods: {},template: `            <App />            `})</script></body></html>

var bus = {}

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body><div id="app"></div><script src="./node_modules/vue/dist/vue.js"></script><script>var bus = {};// 全局组件Vue.component('Parent', {data(){return {msg: 'I am the data of Parent!',};},template: `<div>                    <p> I am the parent component!</p>                    <button @click="consoleFn">button</button>                    <br />                    <BrotherOne />                    <BrotherTwo />                </div>`,methods: {consoleFn(){console.log(bus);},},})Vue.component('BrotherOne', {data(){return {msg: 'I am the data of BrotherOne!',fromBrother: '',};},template: `<div>                    <p> I am the BrotherOne component!</p>                    <p>{{msg}}</p>                    <input v-model="fromBrother" @input="transformData"/>                                       <br />                </div>`,methods: {transformData(){bus['brotherOne'] = {'fromBrother': this.fromBrother,};},},})Vue.component('BrotherTwo', {data(){return {msg: 'I am the data of BrotherTwo!',fromBrother: '',};},template: `<div>                    <p> I am the BrotherTwo component!</p>                    <p>{{msg}}</p>                    <p>fromBrother: {{fromBrother}}</p>                    <button @click="consoleFn" >button</button>                    <br />                </div>`,methods: {consoleFn(){this.fromBrother = bus['brotherOne']['fromBrother'];},},})var App = {template: `<div>                    <Parent />                </div>`,};var vm = new Vue({el: '#app',data(){return {};},components: {App},methods: {},template: `            <App />            `})</script></body></html>