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 相关文章推荐
JS 判断代码全收集
Apr 28 Javascript
jquery中的sortable排序之后的保存状态的解决方法
Jan 28 Javascript
关于jquery的多个选择器的使用示例
Oct 18 Javascript
Jquery网页内滑动缓冲导航的实现代码
Apr 05 Javascript
js限制文本框只能输入中文的方法
Aug 11 Javascript
移动端 一个简单易懂的弹出框
Jul 06 Javascript
详解react native页面间传递数据的几种方式
Nov 07 Javascript
ES6 fetch函数与后台交互实现
Nov 14 Javascript
vue + element-ui的分页问题实现
Dec 17 Javascript
vue中使用mxgraph的方法实例代码详解
May 17 Javascript
详解用js代码触发dom事件的实现方案
Jun 10 Javascript
vue+node 实现视频在线播放的实例代码
Oct 19 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
深入理解php printf() 输出格式化的字符串
2016/05/23 PHP
PHP进制转换实例分析(2,8,16,36,64进制至10进制相互转换)
2017/02/04 PHP
phpstudy2020搭建站点的实现示例
2020/10/30 PHP
会自动逐行上升的文本框
2006/06/30 Javascript
提高jQuery性能的十个诀窍
2013/11/14 Javascript
window.location.href中url中数据量太大时的解决方法
2013/12/23 Javascript
jQuery实现在最后一个元素之前插入新元素的方法
2015/07/18 Javascript
jQuery Validate初步体验(一)
2015/12/12 Javascript
底部悬浮通栏可以关闭广告位的实现方法
2016/06/01 Javascript
jquery 判断selection range 是否在容器中的简单实例
2016/08/02 Javascript
JavaScript中关于for循环删除数组元素内容时出现的问题
2016/11/21 Javascript
javascript实现复选框全选或反选
2017/02/04 Javascript
JS批量替换内容中关键词为超链接
2017/02/20 Javascript
footer定位页面底部(代码分享)
2017/03/07 Javascript
使用 Javascript 实现浏览器推送提醒功能的示例
2017/11/03 Javascript
Angular中使用MathJax遇到的一些问题
2017/12/15 Javascript
jQuery实现输入框的放大和缩小功能示例
2018/07/21 jQuery
vue项目移动端实现ip输入框问题
2019/03/19 Javascript
JS实现给数组对象排序的方法分析
2019/06/24 Javascript
layui实现图片虚拟路径上传,预览和删除的例子
2019/09/25 Javascript
[02:05]2014DOTA2西雅图国际邀请赛 BBC第二天小组赛总结
2014/07/11 DOTA
关于python pyqt5安装失败问题的解决方法
2017/08/08 Python
Python编程把二叉树打印成多行代码
2018/01/04 Python
Python实现的读写json文件功能示例
2018/06/05 Python
Python从list类型、range()序列简单认识类(class)【可迭代】
2019/05/31 Python
python多进程下实现日志记录按时间分割
2019/07/22 Python
python使用opencv在Windows下调用摄像头实现解析
2019/11/26 Python
keras 获取某层的输入/输出 tensor 尺寸操作
2020/06/10 Python
html5 Canvas画图教程(7)—canvas里画曲线之quadraticCurveTo方法
2013/01/09 HTML / CSS
时装界的“朋克之母”:Vivienne Westwood
2017/07/06 全球购物
2013年保送生自荐信格式
2013/11/20 职场文书
公司党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
保密工作整改报告
2014/11/06 职场文书
2016入党心得体会范文
2016/01/06 职场文书
团组织关系介绍信
2019/06/24 职场文书
Java 数据结构七大排序使用分析
2022/04/02 Java/Android