Vue 組件間通訊

prop、event、ref

經過 Prop 向子組件傳遞數據

Prop 是你能夠在組件上註冊的一些自定義特性。當一個值傳遞給一個 prop 特性的時候,它就變成了那個組件實例的一個屬性。爲了給博文組件傳遞一個標題,咱們能夠用一個 props 選項將其包含在該組件可接受的 prop 列表中:html

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

一個組件默承認以擁有任意數量的 prop,任何值均可以傳遞給任何 prop。在上述模板中,你會發現咱們可以在組件實例中訪問這個值,就像訪問 data 中的值同樣。
可使用 v-bind 來動態傳遞 propvue

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
></blog-post>

參考:node


經過事件向父級組件發送消息

Vue 實例提供了一個自定義事件的系統來解決這個問題。咱們能夠調用內建的 $emit 方法並傳入事件的名字,來向父級組件觸發一個事件:git

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

參考:github


訪問元素 & 組件

ref 被用來給元素或子組件註冊引用信息。引用信息將會註冊在父組件的 $refs 對象上。若是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;若是用在子組件上,引用就指向組件實例:vuex

<!-- `vm.$refs.p` will be the DOM node -->
<p ref="p">hello</p>

<!-- `vm.$refs.child` will be the child component instance -->
<child-component ref="child"></child-component>

$parent 屬性能夠用來從一個子組件訪問父組件的實例。設計模式

$children 用來訪問當前實例的直接子組件。api

參考:
訪問元素 & 組件
vm.$refs
vm.$parent
vm.$childrenapp


provide、inject

provide / inject 是 vue 2.2.0 新增的 APIiview

這對選項須要一塊兒使用,以容許一個祖先組件向其全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。若是你熟悉 React,這與 React 的上下文特性很類似。

// 父級組件提供 'foo'
var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}

// 子組件注入 'foo'
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // => "bar"
  }
  // ...
}

參考:


dispatch、broadcast

$dispatch$broadcastVue.js 1.x 中提供的方法。
$dispatch 用於向上級派發事件,只要是它的父級(一級或多級以上),均可以在組件內經過 $on (或 events2.x 已廢棄)監聽到。
$broadcast 是由上級向下級廣播事件的。

參考 $dispatch 和 $broadcast 替換,在 vue2 中已經廢棄了這兩個 API,不過咱們能夠參考 vue1 的源碼在 vue2 中實現這兩個 API

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 || this.$root;
      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);
    }
  }
};

這裏給出幾個組件庫的實現,能夠參考:


findComponents

findComponents 系列方法並非 vueAPI,而是自行實現的經過遞歸、遍歷,找到指定組件的 name 選項匹配的組件實例的方法。
有如下場景:

  • 由一個組件,向上找到最近的指定組件;
  • 由一個組件,向上找到全部的指定組件;
  • 由一個組件,向下找到最近的指定組件;
  • 由一個組件,向下找到全部指定的組件;
  • 由一個組件,找到指定組件的兄弟組件。
// 由一個組件,向上找到最近的指定組件
function findComponentUpward (context, componentName) {
    let parent = context.$parent;
    let name = parent.$options.name;

    while (parent && (!name || [componentName].indexOf(name) < 0)) {
        parent = parent.$parent;
        if (parent) name = parent.$options.name;
    }
    return parent;
}

// 由一個組件,向上找到全部的指定組件
function findComponentsUpward (context, componentName) {
    let parents = [];
    const parent = context.$parent;

    if (parent) {
        if (parent.$options.name === componentName) parents.push(parent);
        return parents.concat(findComponentsUpward(parent, componentName));
    } else {
        return [];
    }
}

// 由一個組件,向下找到最近的指定組件
function findComponentDownward (context, componentName) {
    const childrens = context.$children;
    let children = null;

    if (childrens.length) {
        for (const child of childrens) {
            const name = child.$options.name;

            if (name === componentName) {
                children = child;
                break;
            } else {
                children = findComponentDownward(child, componentName);
                if (children) break;
            }
        }
    }
    return children;
}

// 由一個組件,向下找到全部指定的組件
function findComponentsDownward (context, componentName) {
    return context.$children.reduce((components, child) => {
        if (child.$options.name === componentName) components.push(child);
        const foundChilds = findComponentsDownward(child, componentName);
        return components.concat(foundChilds);
    }, []);
}

// 由一個組件,找到指定組件的兄弟組件
function findBrothersComponents (context, componentName, exceptMe = true) {
    let res = context.$parent.$children.filter(item => {
        return item.$options.name === componentName;
    });
    let index = res.findIndex(item => item._uid === context._uid);
    if (exceptMe) res.splice(index, 1);
    return res;
}

eventbus、vuex

EventBus

EventBus 是一種發佈訂閱設計模式(觀察者設計模式)。
EventBus

  • 有一個全局EventBus
  • 全部事件都訂閱它
  • 全部組件也發佈到它,訂閱組件得到更新
  • 全部組件都可以將事件發佈到總線,而後總線由另外一個組件訂閱,而後訂閱它的組件將獲得更新
var EventBus = new Vue(); 
Object.defineProperties(Vue.prototype, { 
    $bus: { get: function () { 
            return EventBus 
        }
    }
})

這個特定的總線使用兩個方法 $on$emit$emit 用於建立發出的事件;$on 用於訂閱。

var EventBus = new Vue();
this.$bus.$emit('nameOfEvent',{
    // code
});
this.$bus.$on('nameOfEvent',($event) => {
    // code
})

參考:
EventBus
事件總線(EventBus)


Vuex

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
vuex

參考:

相關文章
相關標籤/搜索