详解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 相关文章推荐
JS通过分析userAgent属性来判断浏览器的类型及版本
Mar 28 Javascript
JS创建对象几种不同方法详解
Mar 01 Javascript
Bootstrap每天必学之折叠(Collapse)插件
Apr 25 Javascript
js实现多图左右切换功能
Aug 04 Javascript
jQuery实现为LI列表前3行设置样式的方法【2种方法】
Sep 04 Javascript
Bootstrap菜单按钮及导航实例解析
Sep 09 Javascript
canvas实现简易的圆环进度条效果
Feb 28 Javascript
详解vue2.0脚手架的webpack 配置文件分析
May 27 Javascript
jqgrid实现简单的单行编辑功能
Sep 30 Javascript
el-input 标签中密码的显示和隐藏功能的实例代码
Jul 19 Javascript
基于Vue CSR的微前端实现方案实践
May 27 Javascript
vue自定义插件封装,实现简易的elementUi的Message和MessageBox的示例
Nov 20 Vue.js
浅谈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
提高define性能的php扩展hidef的安装和使用
2011/06/14 PHP
php控制linux服务器常用功能 关机 重启 开新站点等
2012/09/05 PHP
php实现的CSS更新类实例
2014/09/22 PHP
Yii多表联合查询操作详解
2016/06/02 PHP
PHP入门教程之数学运算技巧总结
2016/09/11 PHP
PHP实现的多维数组排序算法分析
2018/02/10 PHP
javascript 无提示关闭窗口脚本
2009/08/17 Javascript
JavaScript类和继承 prototype属性
2010/09/03 Javascript
使用正则表达式的格式化与高亮显示json字符串
2014/12/03 Javascript
AngularJs动态加载模块和依赖注入详解
2016/01/11 Javascript
javascript对象的创建和访问
2016/03/08 Javascript
JS获取子窗口中返回的数据实现方法
2016/05/28 Javascript
JS封装的自动创建表格的实现代码
2016/06/15 Javascript
Vue2.0使用过程常见的一些问题总结学习
2017/04/10 Javascript
javascript修改浏览器title方法 JS动态修改浏览器标题
2017/11/30 Javascript
微信小程序调用摄像头隐藏式拍照功能
2018/08/22 Javascript
layui递归实现动态左侧菜单
2019/07/26 Javascript
JS自定义对象创建与简单使用方法示例
2020/01/15 Javascript
echarts.js 动态生成多个图表 使用vue封装组件操作
2020/07/19 Javascript
微信小程序实现选项卡滑动切换
2020/10/22 Javascript
[53:20]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 VG vs OG
2018/04/03 DOTA
跟老齐学Python之Python文档
2014/10/10 Python
在Python下尝试多线程编程
2015/04/28 Python
python操作ini类型配置文件的实例教程
2020/10/30 Python
HTML最新标准HTML5总结(必看)
2016/06/13 HTML / CSS
canvas绘制圆角头像的实现方法
2019/01/17 HTML / CSS
罗兰·穆雷官网:Roland Mouret
2018/09/28 全球购物
.NET程序员的数据库面试题
2012/10/10 面试题
自荐信怎么写好
2013/11/11 职场文书
2014三八妇女节活动总结范文四篇
2014/03/09 职场文书
初中生评语大全
2014/04/24 职场文书
奥巴马上海演讲稿
2014/09/10 职场文书
2014年防汛工作总结
2014/12/08 职场文书
优秀团员自我评价
2015/03/10 职场文书
2022漫威和DC电影上映作品
2022/04/05 欧美动漫
利用Python实现翻译HTML中的文本字符串
2022/06/21 Python