Vue依赖注入provide与inject

382 阅读3分钟

通过provide与inject进行组件传值

provide与inject的功能是可以把一个祖先组件指定的数据和方法,传递给其所有子孙组件中。 主要在开发高阶插件/组件库时使用, 官网不建议在普通应用程序中直接使用该办法,因为存在管不好的情况。

provide/inject用法

provide/inject:在父级组件中通过provide来提供变量,然后在子级组件中通过inject来注入变量,这里不论子级组件有多深,只要调用了inject那么就可以获取父级组件中provide注入的数据。

语法

provide:是一个对象,或者是一个返回对象的函数。对象中包含要给子孙后代的数据,也就是属性和属性值。

父组件通过provide将自己的数据以对象形式传出去

//对象形式
provide: {
      message: 'provided by father'
    }
//返回对象的函数形式
provide(){
return {
       message: ()=>{ return this.msg}
    }
}

inject:一个字符串数组,或者是一个对象。对象的属性名是子组件中使用的绑定名,对象属性值包含from和default默认值。from是在可用的注入内容中搜索用的 key (字符串或 Symbol),意思就是祖父多层provide提供了很多数据,from属性指定取哪一个key;default指定默认值。

子孙组件:使用注入的属性名作为数据入口接收属性值

//字符串数组
inject:['message']
//对象
inject:{ 
    // 使用一个默认值使其变成可选项
    msg: { // 键名
      from: 'message', // 来源
      default: '' // 默认值
    }

其代码执行顺序是:data->provide->created->mounted

ps:provide 和 inject 绑定并不是可响应的。 即如果在父级组件中改变了传入的数据以后,子级组件并不会得到改变后的值,也就是此时父级组件和子级组件的数据出现了不一致的情况,所以需要人为的设计将数据改为响应式的数据。

当传入的是一个可监听的对象,那么其对象的属性还是可响应的。 也就是当传入的数据是一个字符串,基本数据类型是不可响应的。而当函数返回一个对象,该对象保存了父组件data参数中的数据。此时,数据就可响应了,在父级组件修改了数据,传给子级组件的数据也会被修改,子级组件就要通过调用函数得到传入的数据。

//父级组件
data(){ 
    return { 
        message: "aa"
        }
 }
 provide(){
    return {
        msg:()=>this.message
    }
  }
//子级组件
<div> 信息:{{msg()}} </div>
<div> 信息:{{foo()}} </div>
inject:['msg']
或者
inject: {
    foo: {
      from: 'bar',
      default: () => [1, 2, 3]
    }
  }

基础用法: 传个字符串(数据不是可响应的)

//爷爷组件
<template>
  <div id="app">
    <h1>app组件----{{ msg }}</h1>
    <button @click="msg='app组件数据被修改'">点击修改值</button>
    <two></two>
  </div>
</template>

<script>
import Two from "@/components/Two.vue";

export default {
  data() {
    return {
      msg: "app组件的数据",
    };
  },
  components: {
    Two,
  },
  provide:{
    msg:"app组件的数据"
  }
};
</script>

<style lang="scss">
#app {
  width: 700px;
  height: 700px;
  background-color: goldenrod;
}
</style>
//爸爸组件
<template>
  <div class="two">
    <h1>two组件---{{msg}}</h1>
    <three></three>
  </div>
</template>

<script>
import three from "@/components/three.vue";
export default {
    components:{
        three
    },
    inject:["msg"]
}
</script>

<style lang="scss" scoped="scoped">
    .two{
        width: 500px;
        height: 500px;
        background-color: rgb(7, 251, 251);
    }
</style>
//孙子组件
<template>
    <div class="three">
        <h1>three组件---{{msg}}</h1>
    </div>
</template>

<script>
export default {
    inject:["msg"]
}
</script>

<style lang="scss" scoped="scoped">
.three{
    background-color: purple;
    width: 400px;
    height: 300px;
}
</style>

image.png

设计成响应式的数据

//父级组件
<template>
  <div id="app">
    <h1>app组件----{{ msg }}</h1>
    <button @click="msg='app组件数据被修改'">点击修改值</button>
    <two></two>
  </div>
</template>

<script>
import Two from "@/components/Two.vue";

export default {
  data() {
    return {
      msg: "app组件的数据",
    };
  },
  components: {
    Two,
  },
  provide(){
    return {
      message:()=>{
        return this.msg;
      }
    }
  }
};
</script>

<style lang="scss">
#app {
  width: 700px;
  height: 700px;
  background-color: goldenrod;
}
</style>

//子级组件
<template>
  <div class="two">
    <h1>two组件---{{message()}}</h1>
    <three></three>
  </div>
</template>

<script>
import three from "@/components/three.vue";
export default {
    components:{
        three
    },
    computed:{

    },
    inject:['message']
}
</script>

<style lang="scss" scoped="scoped">
    .two{
        width: 500px;
        height: 500px;
        background-color: rgb(7, 251, 251);
    }
</style>

image.png