父组件与子组件的传参,使用的是props,如果是父组件与孙子组件传参,大部分可能会采用递归的方式,也就是子组件props接收,然后再props传给孙子组件。或者使用vuex。

但如果是迭代的方式,组件的层级越深,不断迭代的props会是代码越来越无法维护,冗余。

于是官方出了provide inject。

provide有父组件设置,inject由子组件接收,他们的特性:

  1. 祖先组件不需要知道哪些后代组件使用它提供的属性
  2. 后代组件不需要知道被注入的属性来自哪里

例子:

父组件

<script>
export default {
 provide: {
    foo: 'bar'
  },
}
</script>

孙子组件

<script>
export default {
  inject: ['foo'],
}
</script>

用法和props差不多,inject也有default属性

<script>
export default {
  inject: {
    foo:{
      default:"默认值"
    }
  }
}
</script>

如果默认的是一个引用类型,也要像props一样,用一个工厂函数抛出

<script>
export default {
  inject: {
    foo:{
      default: ()=> [1,2,3]
    }
  }
}
</script>

如果inject里的key和其他属性发生了冲突,我们可以像model那样,有一个声明

<script>
export default {
  inject: {
    foo1:{
      from: "foo",
      default: ()=> [1,2,3]
    }
  }
}
</script>

from表示其源。

提示:provideinject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。

也就是说,如果传入的是非引用类型的值,父组件修改provide中的属性值,孙子组件并不会响应其变化。

如果是一个引用类型,那么是可以响应到父组件的变化,我们甚至可以使用一个函数来达到响应变化的效果

响应式

函数方式

父组件

<script>
export default {
  data(){
    return {
      color:"blue"
    }
  },
  provide() {
    return {
      color: this.getColor
    } 
  },
  methods:{
    getColor() {
      return this.color;
    },
  }
}
</script>

孙子组件

<template>
  <span>{{color()}}</span>
</template>
<script>
export default {
  inject: ['color'],
}
</script>

通过函数的方式,当父组件中data的color的值发生了变化,子组件依旧可以响应到。

注意一点,如果是传string,可以使用provide为一个对象的形式,如果你要在provide的里面通过this,来获取上下文数据,那么就要如上,使用方法的形式,return出一个对象才行。

性能上估计不太好。

引用类型{}

<script>
export default {
  data(){
    return {
      color:{
        get:"blue"
      }
    }
  },
  provide() {
    return {
      color: this.color
    }
  },
}
</script>

孙子组件

<template>
  <span>{{color.get}}</span>
</template>
<script>
export default {
  inject: ['color'],
}
</script>

这样依旧可以响应到变化,但是不怎么建议使用。

Vue.observable()

这是vue 2.6版本新增的一个api,用于创建一个可监控的对象,大概用起来和vuex相差不了多少,感觉就是一个小型vuex的快速建成方式。

父组件

<script>
import Vue from "vue";
export default {
 provide() {
    this.theme = Vue.observable({
      color: "blue",
    });
    return {
      theme: this.theme,
    };
  },
}
</script>

孙子组件

<template>
  <span>{{theme.color}}</span>
</template>
<script>
export default {
  inject: ['theme'],
}
</script>

这样也可以响应到父组件的color值变化。

但是必须是vue 2.6版本,vue-template-compiler也要同步

//升级vue版本npm 
update vue -S 
//或者 
yarn add vue -Snpm update vue-template-compiler -D 
//或者 
yarn add vue-template-compiler -D

Vue.observable如何更新数据

你可以直接this.theme.color="xxx"来更新,也可以封装一个类似于vuex的mutation方法对象集合。

import vue from 'vue';
export const store =  vue.observable({count: 0});
export const mutation = {
  setCount( count ){
    store.count = count;
  }
}

这种方式可以单独做个js文件,也可以改动一下丢在组件内。

分类: vue 开发实战 标签: vueprovideinject跨组件传参

评论

暂无评论数据

暂无评论数据

目录