vue源碼(二)-vue組件通信方式

vue源碼(二)-vue組件通信方式

一、組件化

組件化開發能夠提高開發效率,方便重複使用簡化調試步驟,提升項目的可維護性,便於多人系統開發

二、通信方式

1.父組件->子組件
1.1通過屬性props進行傳遞

子組件進行定義一個字段msg接受父組件傳遞的參數

<template>
    <div class="hello">
        <h3>{{ msg }}</h3>
    </div>
</template>

<script>
    export default {
      name: 'HelloWorld',
      props: {
        msg: String
      }
    }
</script>

<style scoped>
    h3 {
        margin: 40px 0 0;
    }
</style>

上述代碼中,通過對props中msg的限定,進行接收有父組件傳遞下來的內容,然後在模版文件中通過插槽表達式進行使用。

<HelloWorld msg="用於prop傳遞參數給子組件"/> // 父組件通過msg進行傳遞參數
1.2vm.$attrs
  • 只讀

    包含了父作用域中不作爲 prop 被識別 (且獲取) 的特性綁定 (classstyle 除外)。當一個組件沒有聲明任何 prop 時,這裏會包含所有父作用域的綁定 (classstyle 除外),並且可以通過 v-bind="$attrs" 傳入內部組件——在創建高級別的組件時非常有用。

<template>
    <div class="hello">
        <p>{{$attrs.foo }}</p>
    </div>
</template>

<script>
    export default {
      name: 'HelloWorld'
    }
</script>

<style scoped>
    h3 {
        margin: 40px 0 0;
    }
</style>

上述代碼,通過$attrs屬性進行獲取由父組件傳遞的參數foo,這種方式用於獲取在子組件中props中沒有聲明的屬性,在父組件中使用和1.1使用方式一致

<HelloWorld foo="測試$attrs.foo"/> // 父組件通過foo進行傳遞參數
1.3 vm.$refs
  • 只讀

    一個對象,持有註冊過 ref 特性 的所有 DOM 元素和組件實例。通過給子組件添加ref的形式進行傳遞數據

    如下所示:

    <template>
        <div class="hello">
            <p>{{ age }}</p>
        </div>
    </template>
    <script>
        export default {
          name: 'HelloWorld',
          data: () => {
            return {
              age: '30'
            }
          }
        }
    </script>
    <style scoped>
        h3 {
            margin: 40px 0 0;
        }
    </style>
    

子組件中有數據age,我們能夠在父組件中通過this.$refs.hw.age = '18'的方式進行修改age屬性值

1.4 vm.$children-子元素
  • 只讀

    當前實例的直接子組件。**需要注意 $children 並不保證順序,也不是響應式的。**如果你發現自己正在嘗試使用 $children 來進行數據綁定,考慮使用一個數組配合 v-for 來生成子組件,並且使用 Array 作爲真正的來源。

與1.3同樣的子組件,在父組件通信時,只需要使用this.$children[0].age = '20';方式進行處理age的值即可

2.子組件->父組件通信

通過註冊自定義事件監聽的方式進行傳遞,通過 @click="$emit(‘clickDiv’)"進行派發事件,然後父組件處理的方式

<template>
    <div class="hello" @click="$emit('clickDiv')">
        <h3>{{ msg }}</h3>
    </div>
</template>

<script>
    export default {
      name: 'HelloWorld',
      props: {
        msg: String
      },
      data: () => {
        return {
          age: '30'
        }
      }
    }
</script>

<style scoped>
    h3 {
        margin: 40px 0 0;
    }
</style>

父組件中需要對事件進行監聽

  <div id="app">
    <HelloWorld
            msg="用於prop傳遞參數給子組件"
            foo="測試$attrs.foo"
            ref="hw"
            @clickDiv="onMyClick"
    />


其中onMyClick是父組件中方法,用於處理clickDiv傳遞的數據

3.兄弟之間通信:通過共同的祖輩組件通信

一般通過$parent$root進行處理,利用組件的生命週期進行監聽事件,然後進行處理兄弟節點傳遞的數據

在每個需要監聽的兄弟節點中添加下面監聽事件

      created() {
        // 監聽事件
        this.$parent.$on('hiBrother', () => {
          console.log('來自兄弟的問候', 'HelloWorld');
        });
      },

接着在需要通過兄弟節點的地方進行調用如下代碼:

this.$parent.$emit('hiBrother');

通過上述方式,就能夠實現兄弟之間的通信

4.祖先和後代之間

由於嵌套層級過多,傳遞props不切合實際,可使用provide/inject API完成該任務

provide / inject:

​ 這對選項需要一起使用,以允許一個祖先組件向其所有子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。如果你熟悉 React,這與 React 的上下文特性context很相似。

provide 選項應該是一個對象或返回一個對象的函數。該對象包含可注入其子孫的屬性。在該對象中你可以使用 ES2015 Symbols 作爲 key,但是隻在原生支持 SymbolReflect.ownKeys 的環境下可工作。

inject 選項應該是:

  • 一個字符串數組,或
  • 一個對象,對象的 key 是本地的綁定名,value 是:
    • 在可用的注入內容中搜索用的 key (字符串或 Symbol),或
    • 一個對象,該對象的:
      • from 屬性是在可用的注入內容中搜索用的 key (字符串或 Symbol)
      • default 屬性是降級情況下使用的 value

在父組件進行提供值:

// ancestor
  provide(){
    return {
      provideFoo: '測試provide/inject傳遞信息'
    }
  },

在子組件中進行使用注入值:

// descendant
inject: {
  provideFoo: { default: '這裏設置默認值' }
},
// 或者使用數組形式
inject: ['provideFoo']
5.任意兩個組件之間:事件總線或vuex
  • 事件總線:創建一個公共類負責事件派發、監聽和回調管理
// EventEmit:事件派發、監聽和回調管理
export default class EventEmit {
  constructor() {
    this.callbacks = {};
  }
  $on(name, fn) {
    this.callbacks[name] = this.callbacks[name] || [];
    this.callbacks[name].push(fn);
  }
  $emit(name, args) {
    if (this.callbacks[name]) {
      // 存在 遍歷所有callback
      this.callbacks[name].forEach(cb => cb(args));
    }
  }
}

上述代碼,使用$on進行註冊全局監聽事件、使用$emit進行通知全局處理事件.

當然我們需要將這個公共處理事件類掛在Vue原型上:

import Vue from "vue";
import App from "./App.vue";
import EventEmit from './utils/eventEmit';

// main.js
// 事件總線方式,掛載到Vue中
Vue.prototype.$eventEmit = new EventEmit();

new Vue({
  data: {
    bar: 'bar'
  },
  render: h => h(App),
}).$mount("#app");

在需要使用監聽的地方進行添加監聽

// 創建事件總線
this.$eventEmit.$on('fromHelloWorld', (value) => {
   alert('監聽到由hello world組件傳遞來的數據:' + value);
});

在傳遞觸發的組件中進行觸發

// 派發事件,在HelloWorldEmit.vue組件中監聽
this.$eventEmit.$emit('fromHelloWorld', '傳遞給HelloWorldEmit.vue的數據');
        

觸發的同時,通過第二個參數進行傳值。

以上就是組件之間通信的各種方式。
在這裏插入圖片描述

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