Vue组件间通信的几种方式

vue通信方式有很多,项目中用的比较多的的有pros、vuex、$emit/$on这3种,还有provide/inject(适合高阶组件)、$attrs$listeners(适合高阶组件)以及$parent/$child/ref、eventBus等这3种方式。

1、pros父子组件通信

vue使用props有两种形式形式实现父子组件之间的数据传递。官方描述:props

// 第一种方式
// parent.vue

<template>
  <div>
    <child :message="childName" @change= "changeMessage" />
  </div>
</template>
<script>
import childfrom './child';

export default {
  components: {
    child,
  },
  data() {
    return {
      message: '我是父组件传递的数据',
    };
  },
  methods: {
    changeMessage(val) {
      this.message= val;
    },
  },
};
</script>

// child

<template>
  <div>{{message}}</div>
  <button @click="changeMessage">change</button>
</template>
<script>
export default {
  props: ['message'],
  methods: {
    changeMessage() {
      this.$emit('change', '我是传递给父组件的数据')
    }
  }
};
</script>

父组件通过:message向子组件传递数据,子组件通过$emit触发数据变化,父组件使用$on来监听子组件数据的变化。

// 第二种方式
// parent.vue

<template>
  <div>
    <child v-modle="message" />
  </div>
</template>
<script>
import child from './child';

export default {
  components: {
    child,
  },
  data() {
    return {
      message: '我是父组件传递的数据',
    };
  }
};
</script>

// child

<template>
  <input v-model="sync_value" />
</template>
<script>
import propsync from '@/mixins/propsync'
export default {
  mixins: [propsync],
  props: {
    value: {
      default: '',
      isSync: true
    }
  }
};
</script>

第二种方式是自动化的props双向数据绑定,直接引入mixin,并在配置中声明mixin即可: mixins: [propsync]propsync默认会将所有props创建双向绑定,可通过isSync:false来声明此props不需要创建双向绑定。

 

2、provide/inject

一般适用于高阶组件,祖父组件想多级子组件传递数据,官方描述:provide / inject。以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

provide 选项是:一个对象或返回一个对象的函数
inject 选项是:一个字符串数组,或 一个对象,对象的 key 是本地的绑定名
// parent.vue

<script>
export default {
  provide() {
    message: '我是爷爷'
  },
};
</script>

// child

<script>
export default {
  inject: ['message'],
  created () {
    console.log(this.message) // => "我是爷爷"
  }
};
</script>

 

3、$attrs$listeners

$attr: 向 子组件 传递,当前组件 没有接收的,父组件传递下来的 prop

$listeners: 向父组件传递,当前组件没有接收的,子组件抛出的自定义事件。

// parent.vue

<template>
  <input type="text" v-bind="$attrs" v-on="$listeners">
</template>


// child.vue

<template>
  <input type="text" v-bind="$attrs" @input="observerInput">
</template>
 
<script>
  export default {
    methods: {      
      // 拦截内置事件      
      observerInput (el) {
        this.$emit('input', el.target.value)
      },
    },  
  }
</script>

 

4、eventBus跨组件通信

    class EventBus{
        constructor(){
            this.event=Object.create(null);
        };
        //注册事件
        on(name,fn){
            if(!this.event[name]){
                //一个事件可能有多个监听者
                this.event[name]=[];
            };
            this.event[name].push(fn);
        };
        //触发事件
        emit(name,...args){
            //给回调函数传参
            this.event[name]&&this.event[name].forEach(fn => {
                fn(...args)
            });
        };
        //只被触发一次的事件
        once(name,fn){
            //在这里同时完成了对该事件的注册、对该事件的触发,并在最后取消该事件。
            const cb=(...args)=>{
                //触发
                fn(...args);
                //取消
                this.off(name,fn);
            };
            //监听
            this.on(name,cb);
        };
        //取消事件
        off(name,offcb){
            if(this.event[name]){
                let index=this.event[name].findIndex((fn)=>{
                    return offcb===fn;
                })
                this.event[name].splice(index,1);
                if(!this.event[name].length){
                    delete this.event[name];
                }
            }
        }
    }

声明一个全局Vue实例变量 EventBus , 把所有的通信数据,事件监听都存储到这个变量上。这样就达到在组件间数据共享了,有点类似于 vuex。但这种方式只适用于极小的项目,复杂项目还是推荐 vuex

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章