vue组件之间通信方式实例总结【8种方式】


Posted in Javascript onFebruary 22, 2019

本文实例总结了vue组件之间通信方式。分享给大家供大家参考,具体如下:

对于vue来说,组件之间的消息传递是非常重要的,下面是我对组件之间消息传递的各种方式的总结,总共有8种方式。

1. props和$emit

父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的。

Vue.component('child',{
    data(){
      return {
        mymessage:this.message
      }
    },
    template:`
      <div>
        <input type="text" v-model="mymessage" @input="passData(mymessage)"> </div>
    `,
    props:['message'],//得到父组件传递过来的数据
    methods:{
      passData(val){
        //触发父组件中的事件
        this.$emit('getChildData',val)
      }
    }
  })
  Vue.component('parent',{
    template:`
      <div>
        <p>this is parent compoent!</p>
        <child :message="message" v-on:getChildData="getChildData"></child>
      </div>
    `,
    data(){
      return {
        message:'hello'
      }
    },
    methods:{
      //执行子组件触发的事件
      getChildData(val){
        console.log(val)
      }
    }
  })
  var app=new Vue({
    el:'#app',
    template:`
      <div>
        <parent></parent>
      </div>
    `
  })

在上面的例子中,有父组件parent和子组件child。

1).父组件传递了message数据给子组件,并且通过v-on绑定了一个getChildData事件来监听子组件的触发事件;

2).子组件通过props得到相关的message数据,最后通过this.$emit触发了getChildData事件。

2.$attrs和$listeners

第一种方式处理父子组件之间的数据传输有一个问题:如果父组件A下面有子组件B,组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢?

如果采用第一种方法,我们必须让组件A通过prop传递消息给组件B,组件B在通过prop传递消息给组件C;要是组件A和组件C之间有更多的组件,那采用这种方式就很复杂了。Vue 2.4开始提供了$attrs和$listeners来解决这个问题,能够让组件A之间传递消息给组件C。

Vue.component('C',{
    template:`
      <div>
        <input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)"> </div>
    `,
    methods:{
      passCData(val){
        //触发父组件A中的事件
        this.$emit('getCData',val)
      }
    }
  })
  Vue.component('B',{
    data(){
      return {
        mymessage:this.message
      }
    },
    template:`
      <div>
        <input type="text" v-model="mymessage" @input="passData(mymessage)">
        <!-- C组件中能直接触发getCData的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性 -->
        <!-- 通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的) -->
        <C v-bind="$attrs" v-on="$listeners"></C>
      </div>
    `,
    props:['message'],//得到父组件传递过来的数据
    methods:{
      passData(val){
        //触发父组件中的事件
        this.$emit('getChildData',val)
      }
    }
  })
  Vue.component('A',{
    template:`
      <div>
        <p>this is parent compoent!</p>
        <B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"></B>
      </div>
    `,
    data(){
      return {
        message:'hello',
        messagec:'hello c' //传递给c组件的数据
      }
    },
    methods:{
      getChildData(val){
        console.log('这是来自B组件的数据')
      },
      //执行C子组件触发的事件
      getCData(val){
        console.log("这是来自C组件的数据:"+val)
      }
    }
  })
  var app=new Vue({
    el:'#app',
    template:`
      <div>
        <A></A>
      </div>
    `
  })

3. 中央事件总线

上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。

Vue.component('brother1',{
    data(){
      return {
        mymessage:'hello brother1'
      }
    },
    template:`
      <div>
        <p>this is brother1 compoent!</p>
        <input type="text" v-model="mymessage" @input="passData(mymessage)">
      </div>
    `,
    methods:{
      passData(val){
        //触发全局事件globalEvent
        bus.$emit('globalEvent',val)
      }
    }
  })
  Vue.component('brother2',{
    template:`
      <div>
        <p>this is brother2 compoent!</p>
        <p>brother1传递过来的数据:{{brothermessage}}</p>
      </div>
    `,
    data(){
      return {
        mymessage:'hello brother2',
        brothermessage:''
      }
    },
    mounted(){
      //绑定全局事件globalEvent
      bus.$on('globalEvent',(val)=>{
        this.brothermessage=val;
      })
    }
  })
  //中央事件总线
  var bus=new Vue();
  var app=new Vue({
    el:'#app',
    template:`
      <div>
        <brother1></brother1>
        <brother2></brother2>
      </div>
    `
  })

4. provide和inject

父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。

Vue.component('child',{
    inject:['for'],//得到父组件传递过来的数据
    data(){
      return {
        mymessage:this.for
      }
    },
    template:`
      <div>
        <input type="tet" v-model="mymessage">
      </div>
  })
  Vue.component('parent',{
    template:`
      <div>
        <p>this is parent compoent!</p>
        <child></child>
      </div>
    `,
    provide:{
      for:'test'
    },
    data(){
      return {
        message:'hello'
      }
    }
  })
  var app=new Vue({
    el:'#app',
    template:`
      <div>
        <parent></parent>
      </div>
    `
  })

5. v-model

父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过this.$emit(‘input',val)自动修改v-model绑定的值

Vue.component('child',{
    props:{
      value:String, //v-model会自动传递一个字段为value的prop属性
    },
    data(){
      return {
        mymessage:this.value
      }
    },
    methods:{
      changeValue(){
        this.$emit('input',this.mymessage);//通过如此调用可以改变父组件上v-model绑定的值
      }
    },
    template:`
      <div>
        <input type="text" v-model="mymessage" @change="changeValue">
      </div>
  })
  Vue.component('parent',{
    template:`
      <div>
        <p>this is parent compoent!</p>
        <p>{{message}}</p>
        <child v-model="message"></child>
      </div>
    `,
    data(){
      return {
        message:'hello'
      }
    }
  })
  var app=new Vue({
    el:'#app',
    template:`
      <div>
        <parent></parent>
      </div>
    `
  })

6. $parent和$children

Vue.component('child',{
    props:{
      value:String, //v-model会自动传递一个字段为value的prop属性
    },
    data(){
      return {
        mymessage:this.value
      }
    },
    methods:{
      changeValue(){
        this.$parent.message = this.mymessage;//通过如此调用可以改变父组件的值
      }
    },
    template:`
      <div>
        <input type="text" v-model="mymessage" @change="changeValue">
      </div>
  })
  Vue.component('parent',{
    template:`
      <div>
        <p>this is parent compoent!</p>
        <button @click="changeChildValue">test</button >
        <child></child>
      </div>
    `,
    methods:{
      changeChildValue(){
        this.$children[0].mymessage = 'hello';
      }
    },
    data(){
      return {
        message:'hello'
      }
    }
  })
  var app=new Vue({
    el:'#app',
    template:`
      <div>
        <parent></parent>
      </div>
    `
  })

7. boradcast和dispatch

vue1.0中提供了这种方式,但vue2.0中没有,但很多开源软件都自己封装了这种方式,比如min ui、element ui和iview等。

比如如下代码,一般都作为一个mixins去使用, broadcast是向特定的父组件,触发事件,dispatch是向特定的子组件触发事件,本质上这种方式还是on和on和emit的封装,但在一些基础组件中却很实用。

function broadcast(componentName, eventName, params) {
 this.$children.forEach(child => {
  var name = child.$options.componentName;
  if (name === componentName) {
   child.$emit.apply(child, [eventName].concat(params));
  } else {
   broadcast.apply(child, [componentName, eventName].concat(params));
  }
 });
}
export default {
 methods: {
  dispatch(componentName, eventName, params) {
   var parent = this.$parent;
   var name = parent.$options.componentName;
   while (parent && (!name || name !== componentName)) {
    parent = parent.$parent;
    if (parent) {
     name = parent.$options.componentName;
    }
   }
   if (parent) {
    parent.$emit.apply(parent, [eventName].concat(params));
   }
  },
  broadcast(componentName, eventName, params) {
   broadcast.call(this, componentName, eventName, params);
  }
 }
};

8. vuex处理组件之间的数据交互

如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。

详情可参考:https://vuex.vuejs.org/zh-cn/

希望本文所述对大家vue.js程序设计有所帮助。

Javascript 相关文章推荐
JQuery textlimit 显示用户输入的字符数 限制用户输入的字符数
May 14 Javascript
Javascript中prototype属性实现给内置对象添加新的方法
May 14 Javascript
jQuery实现简洁的导航菜单效果
Nov 23 Javascript
浅析Bootstrap缩略图组件与警示框组件
Apr 29 Javascript
带有定位当前位置的百度地图前端web api实例代码
Jun 21 Javascript
javascript this详细介绍
Sep 19 Javascript
Vue.js之slot深度复制详解
Mar 10 Javascript
JS中mouseup事件丢失的原因与解决办法
Jun 14 Javascript
node.js 用socket实现聊天的示例代码
Oct 17 Javascript
详解微信小程序调起键盘性能优化
Jul 24 Javascript
webpack 静态资源集中输出的方法示例
Nov 09 Javascript
基于vue-cli3+typescript的tsx开发模板搭建过程分享
Feb 28 Javascript
vue2.0中set添加属性后视图不能更新的解决办法
Feb 22 #Javascript
浅谈Node框架接入ELK实践总结
Feb 22 #Javascript
vue工程全局设置ajax的等待动效的方法
Feb 22 #Javascript
JavaScript数据结构与算法之检索算法示例【二分查找法、计算重复次数】
Feb 22 #Javascript
详解基于iview-ui的导航栏路径(面包屑)配置
Feb 22 #Javascript
JavaScript数据结构与算法之检索算法实例分析【顺序查找、最大最小值、自组织查询】
Feb 22 #Javascript
Fundebug支持监控微信小程序HTTP请求错误的方法
Feb 21 #Javascript
You might like
php7 参数、整形及字符串处理机制修改实例分析
2020/05/25 PHP
javascript编程起步(第三课)
2007/02/27 Javascript
javascript 密码强弱度检测万能插件
2009/02/25 Javascript
Javascript 中介者模式实例
2009/12/16 Javascript
JavaScript 学习笔记(十一)
2010/01/19 Javascript
javascript css styleFloat和cssFloat
2010/03/15 Javascript
javascript中返回顶部按钮的实现
2015/05/05 Javascript
Bootstrap按钮组件详解
2016/04/26 Javascript
DWR中各种java方法的调用
2016/05/04 Javascript
jQuery实现简单漂亮的Nav导航菜单效果
2017/03/29 jQuery
详解Angular 4 表单快速入门
2017/06/05 Javascript
详解TypeScript+Vue 插件 vue-class-component的使用总结
2019/02/18 Javascript
vue实现密码显示与隐藏按钮的自定义组件功能
2019/04/23 Javascript
Vue项目中使用better-scroll实现菜单映射功能方法
2019/09/11 Javascript
python基础入门详解(文件输入/输出 内建类型 字典操作使用方法)
2013/12/08 Python
python里将list中元素依次向前移动一位
2014/09/12 Python
python中使用mysql数据库详细介绍
2015/03/27 Python
Python生成不重复随机值的方法
2015/05/11 Python
Python实现程序的单一实例用法分析
2015/06/03 Python
python脚本设置超时机制系统时间的方法
2016/02/21 Python
python下实现二叉堆以及堆排序的示例
2017/09/29 Python
python requests post多层字典的方法
2018/12/27 Python
python算法与数据结构之冒泡排序实例详解
2019/06/22 Python
python 中pyqt5 树节点点击实现多窗口切换问题
2019/07/04 Python
Python常用外部指令执行代码实例
2020/11/05 Python
python-图片流传输的思路及示例(url转换二维码)
2020/12/21 Python
matplotlib相关系统目录获取方式小结
2021/02/03 Python
Matlab使用Plot函数实现数据动态显示方法总结
2021/02/25 Python
欧舒丹美国官网:L’Occitane美国
2018/02/23 全球购物
俄语地区最大的中国商品在线购物网站之一:Umka Mall
2019/11/03 全球购物
北美最大的零售退货翻新商:VIP Outlet
2019/11/21 全球购物
令人啧啧称赞的经理推荐信
2013/11/07 职场文书
环境科学专业个人求职信
2013/12/15 职场文书
大学生的网络创业计划书
2013/12/26 职场文书
《草虫的村落》教学反思
2016/02/20 职场文书
解决Vmware虚拟机安装centos8报错“Section %Packages Does Not End With %End. Pane Is Dead”
2022/06/01 Servers