欢迎来到DIVCSS5查找CSS资料与学习DIV CSS布局技术!
简单的可以把provide/inject对比为React的context,都是为了解决跨层级传递属性的不方便而设立的,跟早期的context一样,一开始provide/inject机制也没有载入官方文档,现在虽然已经写了,但仍是语焉不详,这就是我写本文的目的。
 
Hello World
 
看一个最简单的例子,从祖辈组件中拿到传入下来的颜色值
 
UI界面如上,很简单,祖辈组件还提供了一个单选来改变。
 
<template>
 
  <div>
 
    <label for="red">
 
      红色
 
      <input type="radio" id="red" value="red" v-model="color" />
 
    </label>
 
    <br />
 
    <label for="greed">
 
      绿色
 
      <input type="radio" id="green" value="green" v-model="color" />
 
    </label>
 
    <slot />
 
  </div>
 
</template>
 
先看provide,它可以是一个对象,比如
 
provide: {
 
  color: "green"
 
}
 
在孙子组件中可以顺利的取到这个值,但要注意的是这样子的写法是不能返回Vue实例的响应式数据的,当尝试改为
 
provide: {
 
  color: this.color, //访问不到Vue实例
 
}
 
发生错误,提示是Uncaught TypeError: Cannot read property 'color' of undefined 。
 
一般还是用函数的方式,返回一个传入的对象
 
provide() {
 
  return {
 
    color: this.color,
 
  };
 
}
 
但是color不是响应式的,就是说如果我在祖辈组件里选择另外一个颜色,在孙子组件里是拿不到更新后的值的,关于非响应式这一点在下一节详细展开。
 
inject用来指定一个数组或者一个对象,数组的话就放provide里字段的名称,而对象的话可以指定
 
当前实例中的字段名
 
对应provide里的字段名
 
默认值或者返回默认值的函数
 
const Child = {
 
  inject: {
 
    foo: {
 
      from: 'bar',
 
      default: () => [1, 2, 3]
 
    }
 
  }
 
}
 
不是响应式
 
这个跟React的context是不同的,React没有响应式机制,一旦改变属性后默认会引发层层的渲染,开发者自己通过shouldComponentUpdate来优化。
 
官方文档上明确的说了
 
provide和inject绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
 
第一种解决方案是把值转为函数,记得要用箭头函数,不然不能正确获取this
 
provide() {
 
  return {
 
    color: () => {
 
      return this.color;
 
    },
 
  };
 
}
 
然后使用时就要变成了函数的调用
 
<template>
 
  <div :style="{'color':color()}">传下来的颜色{{color()}}</div>
 
</template>
 
这样子就带来一个很明显的缺点就是由于不是响应式,这个函数将会被调用多次,比如上面模板里有两个color(),可以在函数里打个断点,会发现进来两次。
 
更好一些的解决方案是把provide所在的Vue实例给传递下去,再来改造一下
 
provide() {
 
  return {
 
    color: this,
 
  };
 
}
 
在孙组件里获得的其实是实例了,所以要多取一层属性
 
<template>
 
  <div :style="{'color':color.color}">传下来的颜色{{color.color}}</div>
 
</template>
 
可以看到很多UI组件库就是通过这个方式来传递属性的,因为有可能在不确定层级的子组件里要获得祖组件里的值。以ViewUI为例,来康康树形组件的外层

如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h64073.shtml