iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
自我挑戰組

Vue.js 從零開始系列 第 26

Vue.js 從零開始:provide / inject

component傳遞的最後一個招,前面示範了由內傳到外、外傳到內...等,但是子元件的子元件的子元件,需要父元件資料,我們只能使用props,一個一個往下傳,這時就可以使用provideinject的機制,直接傳遞到想要的子元件上,不管幾層都能達到,根本就是隔山打牛

https://ithelp.ithome.com.tw/upload/images/20211005/20118347J58IMju3mz.png


provide/inject

假設元件是以下的架構

#app
└─ listcomponent
   ├─ list-header
   └─ list-main
      └─ list-footer

在根元件(#app),把需要傳遞的的資料,定義在provide

const app = Vue.createApp({
  data() {
    return {
      text: "隔山打牛"
    };
  },
  provide() {
    return {
      provideText: this.text,
    };
  }
});

在要接收資料的子元件加上inject

components: {
        "list-footer": {
          inject: ["provideText"],
          template: `
          <div>list-footer: {{ provideText }} </div>`
        }
      }

完整範例:

<div id="app">
  <h2>app</h2>
  <list-header></list-header>
</div>
const app = Vue.createApp({
  data() {
    return {
      text: "隔山打牛"
    };
  },
  provide() {
    return {
      provideText: this.text,
      provideText2: Vue.computed(() => this.text)
    };
  }
});
app.component("list-header", {
  template: `
    <div v-for="i in 3">
      list-header:
      <list-main></list-main>
    </div>`,
  components: {
    "list-main": {
      template: `
      <div>
        list-main:
        <list-footer></list-footer>
       </div>`,
      components: {
        "list-footer": {
          inject: ["provideText","provideText2"],
          template: `
          <div>list-footer: {{ provideText }} </div>
          <div>list-footer: {{ provideText2.value }}</div>
          `
        }
      }
    }
  }
});

app.mount("#app");

補充:

透過provide輸出的資料並不會隨著父層資料更新而改變,所以要透過Vue.computed()進行包裝。


Vue.computed()

為了修正provid輸出不會隨父層更新的問題,這邊使用文字輸入框來做示範:

<div id="app">
  <h2>app</h2>
  <input type="text" v-model="text">
  <list-header></list-header>
</div>

v-model綁定datatext,修改裡面的值,並觀察渲染文字的差異。

const app = Vue.createApp({
  data() {
    return {
      text: "隔山打牛"
    };
  },
  provide() {
    return {
      provideText: this.text,
      provideText2: Vue.computed(() => this.text)
    };
  }
});
app.component("list-header", {
  template: `
    <div v-for="i in 3">
      list-header:
      <list-main></list-main>
    </div>`,
  components: {
    "list-main": {
      template: `
      <div>
        list-main:
        <list-footer></list-footer>
       </div>`,
      components: {
        "list-footer": {
          inject: ["provideText","provideText2"],
          template: `
          <div>list-footer: {{ provideText }} </div>
          <div>list-footer: {{ provideText2.value }}</div>
          `
        }
      }
    }
  }
});
app.mount("#app");

  1. provideText2,使用Vue.computed來包裝,子層inject才會跟著連動。
  2. 使用inject接收的子元件,需要加上.value才能正常顯示。

因為使用包裝的computed預設是getter()參數,所以需要使用.value回傳。


參考資料

重新認識 Vue.js


上一篇
Vue.js 從零開:v-bind:is 動態元件
下一篇
Vue.js 從零開始:Vue CLI 介紹與安裝
系列文
Vue.js 從零開始30

尚未有邦友留言

立即登入留言