回到顶部 Fork me on GitHub

通俗易懂了解Vue组件的通信方式

1.前言

        Vue框架倡导组件化开发,力求将一个大的项目拆分成若干个小的组件,就如同我们小时玩堆积木一样,一个大房子是由若干个小积木组成。组件化开发最大问题就是组件之间数据能够流通,即组件之间能够通信。而组件间通信无非就分为三种情况:外层的大组件向内部的小组件通信,内部的小组件向外部的大组件通信,平级之间组件通信。说的官方一点就是:

  • 父组件与子组件通信
  • 子组件与父组件通信
  • 非父子组件通信

针对这三种情况,下面将一一展开介绍。

2.父组件 — —> 子组件

父组件向子组件传递数据通过props。通俗的讲就是:父组件在调用子组件时,在子组件标签内传入形如key=value属性,而子组件内部用props去接住父组件传来的key,进而再拿到传来的value值。

举个栗子:

我们现在有这样一个需求:

在某个项目中,包含了若干个顶部标题栏,而每个顶部标题栏的标题都各不一样,我们希望能够实现一个通用的标题栏组件,使得在之后需要标题栏的地方直接调用这个组件,并只需在调用的时候传入所要显示的标题文字,来满足标题栏相同而标题各不相同的需求。

上述需求是一个经典的父组件向子组件通信(传递数据)的需求,通用的标题栏组件时子组件,父组件是调用该标题栏的父组件,父组件传入不同的标题文字,子组件来渲染父组件所需要的标题。话不多说,直接上代码:

子组件代码:

 1 //子组件代码
 2 <template>
 3     <div class="header">{{ titleText }}</div>
 4 </template>
 5 
 6 <script>
 7     export default {
 8         name: "Child",
 9         props:['title'],
10         data(){
11           return{
12             titleText:this.title
13           }
14         }
15     }
16 </script>
17 
18 <style scoped>
19   .header{
20     width: 100%;
21     height: 100px;
22     background-color: #ccc;
23     text-align: center;
24     font-size: 50px;
25     line-height: 100px;
26   }
27 </style>

父组件代码:

 1 //父组件代码
 2 <template>
 3   <div id="app">
 4     <Child :title="msg"></Child>
 5   </div>
 6 </template>
 7 
 8 <script>
 9 import Child from './Child'
10 export default {
11   name: 'app',
12   components:{
13     Child
14   },
15   data () {
16     return {
17       msg:'难凉热血'
18     }
19   }
20 }
21 </script>
22 
23 <style>
24   *{
25     margin: 0;
26     padding: 0;
27   }
28 </style>

 

从上面代码中,我们可以看到,父组件在调用子组件时,向子组件传递了一个名为title的属性,同时该title属性对应了父组件自己内部的一个值msg,传递过去后,子组件通过自己本身的props选项中的title来接住父组件传过来的值,接着再将拿到的数据应用到自己需要的地方。这样,就完成了父组件向子组件通信的过程。

我们也就完成了上面提出的需求,我们只需在需要标题栏的地方调用该组件并且在调用的时候传入我们想要的title值即可。

3.子组件 — —> 父组件

子组件向父组件传递数据需要借助内建的 $emit 方法通过事件的方式来传递。

$emit方法是vue实例的一个方法,该方法就像一个广播,亦或者像一个信号发射器,该方法接受两个参数:

1 vm.$emit('信号名字',‘信号数据’)
  • 第一个参数:信号名字。即我要发射的这个信号的名字,我有可能发射多个信号,信号名字用于区分各个信号
  • 第二个参数:信号数据。即发射出的真实的信号内容,也就是数据。

再举个栗子:

想象这么一个情景:我军准备发动一次军事行动,行动代号:“打狗”。行动内容:“攻打美国白宫,实现全球统一!!!”那么由中央军委发射信号,军队接收信号。代码如下:

中央军委发射信号:

1 中央军委.$emit('打狗','攻打美国白宫,实现全球统一!!!')

军队接收信号:

1 军队.$on('打狗',function(data){
2    //data就是接收到的信号内容:攻打美国白宫,实现全球统一!!!
3     console.log(data) 
4 })

OK,了解了上述过程,我们就可以实现子组件向父组件通信,由子组件发射信号,父组件接收信号。

子组件代码如下:

 

 1 //子组件代码
 2 <template>
 3   <div class="header">
 4     <p>我是子组件,我要向父组件传递的数据是:{{msg}}</p>
 5     <button @click="emit">发射</button>
 6   </div>
 7 </template>
 8 
 9 <script>
10     export default {
11         name: "Child2",
12         data(){
13           return{
14             msg: "攻打美国白宫,实现全球统一!!!"
15           }
16         },
17         methods:{
18           emit(){
19             this.$emit('dagou',this.msg)
20           }
21         }
22     }
23 </script>
24 
25 <style scoped>
26   .header{
27     width: 100%;
28     height: 100px;
29     background-color: #ccc;
30     text-align: center;
31   }
32 </style>

父组件代码:

 1 //父组件代码
 2 <template>
 3   <div id="app">
 4     <Child @dagou="go"></Child>
 5     <p>我是父组件,我接收到子组件传递的数据是:{{msg}}</p>
 6   </div>
 7 </template>
 8 
 9 <script>
10 import Child from './Child2'
11 export default {
12   name: 'app',
13   components:{
14     Child
15   },
16   data () {
17     return {
18       msg:''
19     }
20   },
21   methods:{
22     go(data){
23       this.msg = data
24     }
25   }
26 
27 }
28 </script>
29 
30 <style>
31   *{
32     margin: 0;
33     padding: 0;
34   }
35 </style>

效果如图:

从上面代码中,我们可以看到,子组件点击发射按钮之后,广播了一个名为dagou的信号,同时发出了信号数据:“攻打美国白宫,实现全球统一!!!”(子组件第19行代码),与此同时,父组件监听@dagou信号(父组件第4行代码),当监听到dagou信号后,调用自身的go函数,同时go函数接受到了传来的数据,这样,就完成了子组件向父组件通信的过程。

4.非父子组件通信

所谓非父子组件,指的是这两个组件没有任何关系,有可能这两个组件各自存在于不同于的父组件内,那么,这种情况下两个组件又该如何通信呢?

在通常情况下,两个非父子组件要进行简单的通信,我们会一般采用中央事件总线的机制,说白了,就是找一个中间传话人,A组件要与B组件说话,那A组件就先给中间传话人说,然后由中间传话人告诉B组件。

那么,在代码中,我们会实例化一个空的vue实例组件用来充当这个中间传话人,请看如下代码:

用于中间传话的空vue组件代码:

 1 //eventBus空组件,什么也不写,只用于传话
 2 <template>
 3     
 4 </template>
 5 
 6 <script>
 7   import Vue from 'vue'
 8   export default new Vue();
 9 </script>
10 
11 <style scoped>
12 
13 </style>

A组件代码:

 1 //A组件代码
 2 <template>
 3     <div>
 4       <p>我是A组件,我要给B组件说:{{toBmsg}}</p>
 5       <button @click="say">对B说</button>
 6     </div>
 7 </template>
 8 
 9 <script>
10     import eventBus from './eventBus'
11     export default {
12         name: "A",
13         data(){
14           return{
15             toBmsg:"hello,我是A组件"
16           }
17         },
18         methods:{
19           say(){
20             eventBus.$emit('haha',this.toBmsg)
21           }
22         }
23     }
24 </script>
25 
26 <style scoped>
27 
28 </style>

B组件代码:

 1 //B组件代码
 2 <template>
 3     <p>我是B组件,我听到A组件给我说:{{msgText}}</p>
 4 </template>
 5 
 6 <script>
 7     import eventBus from './eventBus'
 8     export default {
 9         name: "B",
10         data(){
11           return{
12             msgText:''
13           }
14         },
15       created(){
16           let self = this;
17           eventBus.$on('haha',function (data) {
18             //此处没有用this,是因为此处的this指向了eventBus
19             self.msgText = data
20           })
21       }
22     }
23 </script>
24 
25 <style scoped>
26 
27 </style>

效果如图:

至此,三种情况下的组件间通信的方式介绍完毕。

(完)

posted on 2018-08-18 22:18  难凉热血,码梦为生!  阅读(839)  评论(0编辑  收藏  举报

导航