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


<<:  成为工具人应有的工具包-25 BlueScreenView

>>:  【Day 25】Google Apps Script - API Blueprint 篇 - 执行专案取得 .apib 档

Day-22 操作方法:BOM与DOM

在本系列 JavaScript的重点复习完成後,就要进入笔者学习的最初衷:网页设计应用了。 前提 一...

Swift纯Code之旅 Day24. 「各个TableViewHeader下的Cell显示(1)」

前言 我们已经将TableView的Header给设置完毕了,那可以看到IPhone内建的画面: 两...

Day 30: 机器学习最终回 网路资源总集合

机器学习最终回 网路资源总集合 那麽也到了我们『Machine Learning With Me ,...

Day 09 流程控制

在JavaScript中,想要控制流程,就要设计流程中的条件。 条件判断 if...else 望文生...

Day 13 Compose LazyColumn

今年的疫情蛮严重的,希望大家都过得安好,希望疫情快点过去,能回到一些线下技术聚会的时光~ 今天目标:...