详解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时间自动刷新实现原理与步骤
Jan 06 Javascript
js实现带圆角的两级导航菜单效果代码
Aug 24 Javascript
jQuery多级手风琴菜单实例讲解
Oct 22 Javascript
将json转换成struts参数的方法
Nov 08 Javascript
vue.js实例todoList项目
Jul 07 Javascript
angular2路由切换改变页面title的示例代码
Aug 23 Javascript
vue-router 路由基础的详解
Oct 17 Javascript
开发Vue树形组件的示例代码
Dec 21 Javascript
浅析JS中NEW的实现原理及重写
Feb 20 Javascript
Vue打包部署到Nginx时,css样式不生效的解决方式
Aug 03 Javascript
JavaScript 空间坐标的使用
Aug 19 Javascript
基于JavaScript实现简单扫雷游戏
Jan 02 Javascript
浅谈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
mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别
2009/04/24 PHP
用php或asp创建网页桌面快捷方式的代码
2010/03/23 PHP
php 各种应用乱码问题的解决方法
2010/05/09 PHP
PHP多线程编程之管道通信实例分析
2015/03/07 PHP
PHP判断json格式是否正确的实现代码
2017/09/20 PHP
PHP常用函数之base64图片上传功能详解
2019/10/21 PHP
nodejs中exports与module.exports的区别详细介绍
2013/01/14 NodeJs
多个表单中如何获得这个文件上传的网址实现js代码
2013/03/25 Javascript
js模仿windows桌面图标排列算法具体实现(附图)
2013/06/16 Javascript
图片动画横条广告带上下滚动可自定义图片、链接等等
2013/10/20 Javascript
javascript阻止scroll事件多次执行的思路及实现
2013/11/08 Javascript
jquery使用淘宝接口跨域查询手机号码归属地实例
2013/11/28 Javascript
jQuery中:password选择器用法实例
2015/01/03 Javascript
js实现的捐赠管理完整实例
2015/01/20 Javascript
JavaScript父子窗体间的调用方法
2015/03/31 Javascript
JS数组array元素的添加和删除方法代码实例
2015/06/01 Javascript
使用jQuery Ajax 请求webservice来实现更简练的Ajax
2016/08/04 Javascript
Vue.js教程之计算属性
2016/11/11 Javascript
基于iScroll实现内容滚动效果
2018/03/21 Javascript
js数组去重的N种方法(小结)
2018/06/07 Javascript
使用vue-router为每个路由配置各自的title
2018/07/30 Javascript
详解Require.js与Sea.js的区别
2018/08/05 Javascript
当vue路由变化时,改变导航栏的样式方法
2018/08/22 Javascript
ES6 更易于继承的类语法的使用
2019/02/11 Javascript
python 迭代器和iter()函数详解及实例
2017/03/21 Python
基于Django用户认证系统详解
2018/02/21 Python
Python设计模式之职责链模式原理与用法实例分析
2019/01/11 Python
新手入门Python编程的8个实用建议
2019/07/12 Python
Python模块汇总(常用第三方库)
2019/10/07 Python
Python基于DB-API操作MySQL数据库过程解析
2020/04/23 Python
html5 video标签屏蔽右键视频另存为的js代码
2013/11/12 HTML / CSS
高中毕业自我鉴定
2013/12/16 职场文书
出国签证在职证明
2014/01/16 职场文书
幼儿园中秋节活动反思
2014/02/16 职场文书
2016年先进教师个人事迹材料
2016/02/26 职场文书
Python OpenCV超详细讲解调整大小与图像操作的实现
2022/04/02 Python