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

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