美文网首页
vue 的 provide, inject在使用时的一个小问题

vue 的 provide, inject在使用时的一个小问题

作者: 0月 | 来源:发表于2021-10-28 00:20 被阅读0次

背景

项目中有个需求,需要tab形式展示不确定个数的内容,要求可配置,于是我设计了个组合组件: tab.vue, tabContent.vue 父子配合完成tab切换功能

问题

然后父子组件需要通信了,tab.vue 切换tab的时候需要通知tabContent.vue, 假如有两个tab A, B ;点击tab header A的时候, 显示tabContent A ,tabContent B隐藏 ;点击tab header B的时候, 显示B ,A隐藏, 怎么无感通知呢?我采用了组合组件通用的手段: provide, inject

tab.vue :

<div>
  <ul>
    <li 
      v-for="tabName in tabNames"
      :key="tabName"
      @click="currentTab = tabName"
    >
        {{tabName }}
    </li>
  </ul>
  <div> <slot /> </div>
</div>

 props: {
   tabNames: {
      type: Array,
       required: true
    },
},
data() {
  return {
    currentTab: this.tabNames[0]
  }
},
provide: {
  tab: this //  传tab实例下去给tabContent
}

tabContent.vue :

<div v-show="tab.currentTab === tabName">
  <slot />
</div>
inject: ['tab'], // 拿到tab
props: {
  tabName: {
    type: String,
    required: true
  }
},

设计出来,看起来没啥问题

<tab :tabNames="['A', 'B']">
  <tabContent tabName="A">A</tabContent>
  <tabContent tabName="B">B</tabContent>
</tab>

但是跑起来就是失效 ,A B都没有显示。在tabContent created钩子打印排查发现是this指向undefined了

// tabContent.vue
created() {console.log(this.tab)},

方案

知道问题, 那就好解决了,把this绑定到tab实例就好,但是

provide: {
  tab: this //  传tab实例下去给tabContent
}

怎么绑定呢?查看文档,会有另外一种用函数的方式

provide() {
  return {
    tab: this //  传tab实例下去给tabContent
  }
}

结果

解决了问题

但是为什么会这样子呢?多年的经验告诉我应该是底层函数会通过call apply的方式绑定了this到实例上
看看源码:


init.png
initProvide

有人说不推荐在业务中使用provide inject。为什么? 因为这东西在祖先组件注入会污染所有后代,同样假如有多层祖先组件,后代就不确定是哪个祖先传下来的了,不好维护。

所以基于以上考虑,只适合在一些强耦合的组合组件中使用。 如

  • el-select, el-option
  • el-tab, el-tab-pane
  • el-table, el-table-colunm

相关文章