Vue躬行記(5)——組件通信


  組件之間除了保持獨立之外,還需要相互通信,本章將介紹幾種通信的方式。

一、直接訪問

  Vue提供了三個實例屬性,可直接訪問父組件、子組件和根實例,如下所列。

  (1)$parent:父組件。

  (2)$root:根實例,如果沒有父實例,那么讀取的將是自身。

  (3)$children:直接子組件,無法獲取隔代的子組件,並且不保證組件的順序,也非響應式。

  下面用一個示例來演示它們的用法,首先創建兩個父子關系的組件parent和child;接着初始化根實例vm,掛載的<div>元素包含parent組件;最后為根實例和parent組件的數據對象添加name屬性。

<div id="container">
  <parent></parent>
</div>
<script>
  Vue.component("child", {
    template: '<p>子組件</p>',
    mounted: function() {
      this.$parent.name;      //"parent"
      this.$root.name;        //"root"
    }
  });
  Vue.component("parent", {
    data: function() {
      return {
        name: "parent"
      };
    },
    template: '<child></child>'
  });
  var vm = new Vue({
    el: "#container",
    data: {
      name: "root"
    }
  });
  vm.$children;            //[VueComponent]
</script>

  當執行vm.$children時,得到的是一個子組件數組。在child組件的mounted鈎子中調用了實例的$parent和$root的name屬性,其值分別是“parent”和“root”。

  大部分情況下,應當避免直接修改組件的內部,因為這么做不僅讓父子組件緊密耦合,而且還難以追蹤是誰發起的變更。

二、ref和$refs

  如果要直接訪問子元素或子組件,那么除了使用上文的$children屬性之外,還能通過ref特性配合$refs屬性實現。

  DOM元素或組件可通過聲明ref特性來指定一個索引標識符,即注冊引用信息。而父組件的$refs屬性則記錄了聲明過ref特性的子元素和子組件,它的值是一個對象,其鍵就是ref特性的值。下面是一個簡單的例子,注冊了父組件parent和子組件child,並且為child組件和<input>元素分別聲明了ref特性。

Vue.component("child", {
  template: '<input ref="txt" />',
  mounted: function() {
    this.$refs;        //{txt: input}
  }
});
Vue.component("parent", {
  template: '<child ref="child"></child>',
  mounted: function() {
    this.$refs;        //{child: VueComponent}
  }
});

  在兩個組件的mounted鈎子中,讀取了各自實例的$refs屬性。如果要在parent組件中讀取child組件的$refs屬性,那么可以像下面這樣。

this.$refs.child.$refs

  注意,$refs不是響應式的,並且在渲染到頁面之前是無法訪問的,即不能在mounted之前的鈎子中使用。

  當ref特性與v-for指令配合時,引用的將是一個數組,如下所示。

Vue.component("child", {
  data: function() {
    return {
      names: ["strick", "freedom"]
    };
  },
  template: `<div>
      <input v-for="item in names" ref="txt" />
    </div>`,
  mounted: function() {
    this.$refs;     //{txt: [input, input]}
  }
});

三、自定義事件

  組件支持自定義事件,並且能在子組件中觸發該事件,從而實現組件之間的通信。假設有兩個父子關系的組件parent和child,在child組件上聲明了自定義的dot事件,而在<button>元素上添加了click事件,它們接收的事件處理程序都叫add,如下所示。

Vue.component("child", {
  template: '<button @click="add">提交</button>',
  methods: {
    add: function() {
      this.$emit("dot", 1, 2);
    }
  }
});
Vue.component("parent", {
  template: '<child @dot="add"></child>',
  methods: {
    add: function(left, right) {
      console.log(left, right);        //1 2
    }
  }
});

  Vue提供的實例方法$emit(),它的第一個參數是要觸發的事件名稱,其余參數都將回傳給該事件的處理程序。在子組件child的add()方法中向$emit()傳遞了三個參數(“dot”、1和2),父組件parent中的add()方法能接收從子組件傳遞過來的兩個數值(1和2)。

  注意,自定義的事件名稱不要用駝峰的命名方式,因為它沒有等價的連字符分隔式的名稱,例如下面的addNumber和add-number是兩個事件。

<child @addNumber="handle"></child>
<!-- 不同 -->
<child @add-number="handle"></child>

  在DOM模板中,由於事件名稱會被自動轉換為小寫,因此像下面這樣調用addNumber事件將會失敗。但在字符串模板中不會受其影響,依然能調用成功。

this.$emit("addNumber");

1)v-model

  組件也支持v-model指令,但需要做些配置。默認情況下,組件的v-model只監聽value特性的變化以及input事件。如果要定制,那么可以使用model選項,並且需要在props中添加要監聽的特性。下面注冊一個checkbox組件,並讓它的v-model指令關聯模板內的復選框的checked特性和change事件。

Vue.component("checkbox", {
  model: {
    prop: "checked",
    event: "change"
  },
  props: {
    checked: Boolean
  },
  template: '<input type="checkbox" :checked="checked" @change="dot" />',
  methods: {
    dot: function(e) {
      console.log(e.target.checked);
    }
  }
});

  在將v-model作用於checkbox組件上后(如下所示),每次點擊渲染出的復選框,就會在控制台輸出當前的選中狀態。

<div id="container">
  <checkbox v-model="current"></checkbox>
</div>
<script>
  var vm = new Vue({
    el: "#container",
    data: {
      current: true
    }
  });
</script>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM