详解Vue组件之间通信的七种方式


Posted in Javascript onApril 14, 2019

使用Vue也有很长一段时间,但是一直以来都没对其组件之间的通信做一个总结,这次就借此总结一下。

父子组件之间的通信

1)props和$emit

父组件通过props将数据下发给props,子组件通过$emit来触发自定义事件来通知父组件进行相应的操作
具体代码如下:

  

```
    // 父组件
    <template>
      <div>
        <h3>props和$emit</h3>
        <Children v-on:changeMsg="changeMsg" :msg="msg"/>
      </div>
    </template>
    <script>
    import Children from './children';
    export default {
      data() {
        return {
          msg: '传递的值'
        }
      },
      components: {
        Children
      },
      methods: {
        changeMsg(val) {
          this.msg = val;
        }
      }
    }
    </script>
    // 子组件
    <template>
      <div>
        <h3 @click="notify">{{msg}}</h3>
      </div>
    </template>
    
    <script>
    export default { 
      data(){
        return {
    
        }
      }, 
      props: ['msg'],
      methods: {
        notify() {
          this.$emit('changeMsg', '修改后的');
        }
      }
    }
    </script>
  ```

2)vm.$parent和vm.$children

vm.$parent: 父实例,如果当前实例有的话

vm.$children: 获取当前实例的直接直接子组件,需要注意的是$children并不保证顺序,也不是响应式的

具体代码如下:

  

```
    // 父组件的代码
    <template>
      <div>
        <h3>{{title}}</h3>
        <button @click="amend">在父组件中修改子组件的标题</button>
        <Children />
      </div>
    </template>
    
    <script>
    import Children from './children.vue';
    export default {
      data() {
        return {
          title: '父组件'
        }
      },
      components: {
        Children
      },
      methods: {
        amend() {
          this.$children[0].title = '修改后的子组件标题';
        }
      }
    }
    </script>
    // 子组件的代码
    <template>
      <div>
        <h3>{{title}}</h3>
        <button @click="amend">在子组件中修改父组件的标题</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          title: '子组件'
        }
      },
      methods: {
        amend() {
          this.$parent.title = '修改后的父组件标题';
        }
      }
    }
    </script>
  ```

3)自定义事件的v-model

https://cn.vuejs.org/v2/guide/components-custom-events.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BB%84%E4%BB%B6%E7%9A%84-v-model
具体代码如下:

  

```
    // 父组件
    <template>
      <div>
        标题:<input type="text" v-model="mymessage"><br />
        <Children v-model="mymessage" />
      </div>
    </template>
    
    <script>
    import Children from './children.vue';
    export default {
      data() {
        return {
          mymessage: '名字',
        }
      },
      components: {
        Children
      }
    }
    </script>
    // 子组件
    <template>
      <div>
        <input type="text" :value="mymessage" @input="changeValue"> 
      </div>
    </template>
    
    <script>
    export default {
      model: {
        prop: 'mymessage',
        event: 'input'
      },
      props: ['mymessage'],
      methods: {
        changeValue(event){
          this.$emit('input', event.target.value);
        }
      }
    }
    </script>
  ```

祖先组件和其子孙组件通信

1)provide/inject

provide/inject,允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下文关系成立的时间里始终生效

https://cn.vuejs.org/v2/api/#provide-inject     

具体代码如下:

   

```
    // 父组件
    <template>
      <div>
        <h3>{{title}}</h3>
        <Children />
      </div>
    </template>
    
    <script>
    import Children from './children.vue';
    export default {
      data() {
        return {
          title: '父组件的标题'
        }
      },
      provide() {
        return {
          updateTitle: this.updateTitle
        }
      },
      methods: {
        updateTitle(title) {
          this.title = title;
        }
      },
      components: {
        Children
      }
    }
    </script>
    // 子组件
    <template>
      <div>
        <button @click="changeAttr">修改父组件的属性</button>
        <Grandson />
      </div>
    </template>
    
    <script>
    import Grandson from './grandson.vue';
    export default {
      data() {
        return {
          
        }
      },
      inject: ['updateTitle'],
      methods: {
        changeAttr() {
          this.updateTitle('子组件修改标题');
        }
      },
      components: {
        Grandson
      }
    }
    </script>
    // 孙组件
    <template>
      <div>
        <button @click="changeAttr">修改祖先组件的属性</button>
      </div>
    </template>
    
    <script>
    export default {
      inject: ['updateTitle'],
      methods: {
        changeAttr() {
          this.updateTitle('孙组件修改标题');
        }
      }
    }
    </script>
  ```

2)$attrs和$listeners

组件A下面有一个组件B,组件B下面有一个组件C,如果想将组件A的数据和自定义事件传递给组件C,就可以使用$attrs和$listeners。

vm.$attrs: 当一个组件没有声明任何 prop 时(没有在props声明属性),这里会包含所有父作用域的绑定 ,并且可以通过 v-bind="$attrs" 传入内部组件

vm.$listeners: 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件。

https://cn.vuejs.org/v2/api/#vm-attrs

具体代码如下:

```
  // 父组件
  <template>
    <div>
      <Children :msg="msg" v-on:changeMsg="changeMsg"/>
    </div>
  </template>
  
  <script>
  import Children from './children';
  export default {
    data() {
      return {
        msg: '下发数据',
        test: '123'
      }
    },
    components: {
      Children
    },
    methods: {
      changeMsg() {
        this.msg = '修改后的数据';
      }
    }
  }
  </script>
  // 子组件
  <template>
    <div>
      <Grandson v-bind="$attrs" v-on="$listeners"/>
    </div>
  </template>
  
  <script>
  import Grandson from './grandson';
  export default {
    components: {
      Grandson
    }
  }
  </script>
  // 孙组件
  ```
    <template>
      <div>
        <h3>{{$attrs.msg}}</h3>
        <button @click="change">修改数据</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
    
        }
      },
      methods: {
        change() {
          this.$emit('changeMsg')
        }
      }
    }
    </script>

  ```
```

非父子组件之间的通信

通过中央事件总线来进行通信

通过新建一个Vue事件的bus对象,然后通过bus.$emit来触发事件,bus.$on监听触发的事件。使用中央事件总线时,需要在手动清除它,不然它会一直存在,原本只执行一次的操作,将会执行多次。

具体代码如下:

```
    // 父组件
    <template>
      <div>
        <One />
        <Two />
      </div>
    </template>
    <script>
    import One from './one.vue';
    import Two from './two.vue';
    export default {
      data() {
        return {
        }
      },
      components: {
        One,
        Two
      }
    }
    </script>
    // one组件
    <template>
      <div>
        <h3>第一个组件</h3>
        <button @click="add">增加数量</button>
      </div>
    </template>
    <script>
    import {BUS} from './index.js';
    export default {
      data() {
        return {
        }
      },
      methods: {
        add() {
          BUS.$emit('add');
        }
      },
      beforeDestory() {
        BUS.$off('add');
      }
    }
    </script>
    // two组件
    <template>
      <div>
        <h3>第二个组件</h3>
        <h3>数量: {{num}}</h3>
      </div>
    </template>
    <script>
    import {BUS} from './index.js';
    export default {
      data() {
        return {
          num: 1
        }
      },
      mounted() {
        BUS.$on('add', () => {
          this.num += 1;
        })
      },
      beforeDestroy() {
        BUS.$off('add');
      }
    }
    </script>
    // index.js 创建的bus
    import Vue from 'vue';
    export const BUS = new Vue({
    }) 
  ```

通过vuex来进行数据管理,具体内容见vuex官网

如果有什么不对的地方,或者还有什么方法我没有写到,希望大家可以提出来,谢谢。

总结

以上所述是小编给大家介绍的Vue组件之间通信的七种方式,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
Javascript select下拉框操作常用方法
Nov 09 Javascript
jQuery中的.bind()、.live()和.delegate()之间区别分析
Jun 08 Javascript
JS实现div内部的文字或图片自动循环滚动代码
Apr 19 Javascript
jquery实现页面图片等比例放大缩小功能
Feb 12 Javascript
JavaScript中的全局对象介绍
Jan 01 Javascript
JavaScript获取DOM元素的11种方法总结
Apr 25 Javascript
javascript经典特效分享 手风琴、轮播图、图片滑动
Sep 14 Javascript
Javascript 实现简单计算器实例代码
Oct 23 Javascript
Bootstrap中定制LESS-颜色及导航条(推荐)
Nov 21 Javascript
JavaScript中localStorage对象存储方式实例分析
Jan 12 Javascript
使用bootstrap插件实现模态框效果
May 10 Javascript
jQuery实现滚动效果
Nov 17 jQuery
浅谈Vue CLI 3结合Lerna进行UI框架设计
Apr 14 #Javascript
vue使用axios上传文件(FormData)的方法
Apr 14 #Javascript
详解如何理解vue的key属性
Apr 14 #Javascript
axios+Vue实现上传文件显示进度功能
Apr 14 #Javascript
Vue 使用formData方式向后台发送数据的实现
Apr 14 #Javascript
说说如何使用Vuex进行状态管理(小结)
Apr 14 #Javascript
基于Vue2-Calendar改进的日历组件(含中文使用说明)
Apr 14 #Javascript
You might like
PHP实现变色验证码实例
2014/01/06 PHP
php实现猴子选大王问题算法实例
2015/04/20 PHP
Yii框架参数配置文件params用法实例分析
2019/09/11 PHP
php7 图形用户界面GUI 开发示例
2020/02/22 PHP
jQuery EasyUI API 中文文档 - Spinner微调器使用
2011/10/21 Javascript
checkbox全选所涉及到的知识点介绍
2013/12/31 Javascript
JS文本获得焦点清除文本文字的示例代码
2014/01/13 Javascript
jQuery中contents()方法用法实例
2015/01/08 Javascript
JS更改select内option属性的方法
2015/10/14 Javascript
easyui datebox 时间限制,datebox开始时间限制结束时间,datebox截止日期比起始日期大的实现代码
2017/01/12 Javascript
JS出现失效的情况总结
2017/01/20 Javascript
jQuery中on方法使用注意事项详解
2017/02/15 Javascript
基于JavaScript实现无限加载瀑布流
2017/07/21 Javascript
解决bootstrap模态框数据缓存的问题方法
2018/08/10 Javascript
Vuex 快速入门(简单易懂)
2018/09/20 Javascript
JavaScript模板引擎应用场景及实现原理详解
2018/12/14 Javascript
详解JS浏览器事件循环机制
2019/03/27 Javascript
用Python的urllib库提交WEB表单
2009/02/24 Python
Python 正则表达式(转义问题)
2014/12/15 Python
老生常谈python之鸭子类和多态
2017/06/13 Python
Python程序员面试题 你必须提前准备!(答案及解析)
2018/01/23 Python
python 实现对数据集的归一化的方法(0-1之间)
2018/07/17 Python
Pytorch之finetune使用详解
2020/01/18 Python
python如何求数组连续最大和的示例代码
2020/02/04 Python
python 如何上传包到pypi
2020/12/24 Python
上海微创软件面试题
2012/06/14 面试题
应届生服装设计自我评价
2013/09/20 职场文书
平面设计自荐信
2013/10/07 职场文书
应届生个人求职信模板
2013/11/26 职场文书
善意的谎言事例
2014/02/15 职场文书
房屋租赁协议书范本
2014/04/10 职场文书
广播体操口号
2014/06/18 职场文书
2014年初中班主任工作总结
2014/11/08 职场文书
评测 | 大屏显示带收音机的高端音箱,JBL TUNE2便携式插卡音箱实测
2021/04/24 无线电
Python实战之实现简易的学生选课系统
2021/05/25 Python
阿里云服务器部署RabbitMQ集群的详细教程
2022/06/01 Servers