前言

父子组件传参可以通过propsemit来实现,但是当组件的层次结构比较深时,propsemit就没什么作用了。vue为了解决这个提出了Provide / Inject,知道这个东西,但是一直没用过,最近碰到了一个问题,踩了一些坑,在这里记录一下

备注:
我安装的是vue3.x,v-model用的是3.x的语法。
2.x和3.x用法一致,我这里是用2.x写的

通用知识

基本用法

provide 选项应该是:一个对象或返回一个对象的函数
inject 选项应该是:一个字符串数组,或 一个对象,对象的 [key] 是本地的绑定名

provide 和 inject 绑定并不是可响应的。这是刻意为之的。

代码执行顺序

data->provide->created->mounted

基本代码

主要使用grandpagrandson这两个组件,son在这里充当一个层级

//grandpa.vue
<template>
  <div>
    <h3 style="margin-bottom: 20px">爷爷组件</h3>
    <el-button type="primary" @click="lookDetail">查看</el-button>
    <!-- 儿子组件 -->
    <son v-model:visible="openDialog"></son>
  </div>
</template>

<script>
import Son from "./son.vue";
export default {
  components: { Son },
  data() {
    return {
      message: "aa",
      openDialog: false,
    };
  },
  methods: {
    lookDetail() {
      this.openDialog = true;
    },
  },
};
</script>


//son.vue
<template>
  <div>
    <el-dialog  v-model="visible" title="父组件" width="50%" append-to-body @close="closeDialog">
      <el-button type="primary" @click="lookDetail">查看</el-button>
    </el-dialog>
    <!-- 孙子组件 -->
    <grandson v-model:visible="openDialog"></grandson>
  </div>
</template>

<script>
//孙子组件
import grandson from "./grandson.vue";
export default {
  components: {
    grandson,
  },
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
  },
  emit: ["update:visible"],
  data() {
    return {
      openDialog: false,
    };
  },
  methods: {
    closeDialog() {
      this.$emit("update:visible", false);
    },
    lookDetail() {
      this.openDialog = true;
    },
  },
};
</script>


//grandson.vue
<template>
  <div>
    <el-dialog v-model="visible" title="孙子组件"  width="30%"  @close="closeDialog">
    </el-dialog>
  </div>
</template>

<script>
export default {
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
  },
  emit: ["update:visible"],
  data() {
    return {};
  },
  methods: {
    closeDialog() {
        this.$emit("update:visible",false)
    },
  },
};
</script>

如图:
在这里插入图片描述

基础用法: 传个字符串

简单修改一下组件

//grandpa.vue
export default {
  components: { Son },
  provide:{
     grandpaMsg:'哈哈哈'
  }


//grandson.vue
<template>
  <div>
    <el-dialog  v-model="visible"  title="孙子组件"  width="30%"  @close="closeDialog">
        <div>
            信息:{{grandpaMsg}}
        </div>
    </el-dialog>
  </div>
</template>

<script>
export default {
  props: {
    visible: {
      type: Boolean,
      default: false,
    },
  },
  inject:['grandpaMsg'],

数据过来了,如图:
在这里插入图片描述
中级用法
传个字符串没啥用,如果要传data里的一个属性呢?简单修改一下组件

//grandpa.vue
 components: { Son },
 provide:{
    grandpaMsg:this.message
 },
 data() {
   return {
     message: "aa",
     openDialog: false,
   };
 },

嗯,直接报错,哈哈哈。
在这里插入图片描述
如果要使用data里的参数,需要这样写

//grandpa
 components: { Son },
 provide(){
    return {
        grandpaMsg:this.message
    }
},

结果:
在这里插入图片描述
高级用法
一开始就说了这个不是响应式,简单看一下

<h3 style="margin-bottom: 20px">爷爷组件</h3>
 <el-button type="primary" @click="lookDetail">查看</el-button>
 <el-button type="primary" @click="message='abcde'">改变数据</el-button>

如图:
在这里插入图片描述
那如何变成响应式的呢,再简单改一下

//grandpa
 provide(){
    return {
        grandpaMsg:()=>this.message
    }
  },

//grandson
<el-dialog  v-model="visible"  title="孙子组件"  width="30%"  @close="closeDialog">
      <div>
          信息:{{grandpaMsg()}}
      </div>
  </el-dialog>

如图:

在这里插入图片描述

拓展:你可以直接传一个this过去,这样孙子组件会获得爷爷组件的实例对象,这种方式也是响应式的

 provide(){
    return {
        grandpaMsg:this
    }
 },
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐