从原理到实战:vue中的provide/inject让你的代码更优美

2023-05-16

前言

关于 vue 中的 provide/inject 这一主题,它可以被看作是一种高级的依赖注入机制,允许跨层级组件实现状态共享,从而提高代码的可维护性和扩展性。在这篇文章中,我将从原理到实战带大家由浅入深探究这个机制的底层原理和具体使用方法,无论你是 vue 的初学者还是经验丰富的开发者,相信本文都将对你有所帮助。


vue 的通信方式

vue 中组件之间交互通信有很多种方式,props传值、emit传值、bus传值等等,相信大多数同学对此都不陌生,不太清楚的同学也可以 『点此』 查看博主往期的文章,其中有详细的讲解。话说回来,当组件的层次结构比较深时,propsemit 就没什么作用了。这个时候,vue 提出了 Provide / Inject

在这里插入图片描述


1、Provide / Inject是什么?

文章开头这张图,很好地诠释了 provide/inject 的核心,但是可能很多同学并没有看出其中端倪,别急,文章最后,还是这张图,你一定会恍然大悟。

provide/inject 这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。通俗说就是可以用父组件给祖孙组件进行传值,也就是可以隔代传值,不论子组件有多深,只要调用了 inject 那么就可以注入 provider 中的数据,而不是局限于只能从当前父组件的 props 属性来获取数据,这也是 provide/inject 最大的特性。

provide 提供变量

provide 是一个对象,或者是一个返回对象的函数。里面呢就包含要给子孙后代的东西,也就是属性和属性值。

inject 注入变量

inject 是一个字符串数组,或者是一个对象。属性值可以是一个对象,包含 formdefault 默认值。


类型

provide

Object | () => Object

inject

Array<string> | { [key: string]: string | Symbol | Object }

代码执行顺序

data->provide->created(在这个阶段$el还未生成,在这先处理privide的逻辑,子孙组件才可以取到inject的值)->mounted

注意:

provideinject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。根据官方要求,我们只需要传入对象过去,并且对象是响应式的,定义在 data 或者计算属性里都可以。


2、实例

相信看完上面的内容,你已经对 provideinject 有了初步的认识和了解,但是说了这么多,终究都是理论,秉持着实践出真知的原则,下面我们进行代码实践。


文件结构

在这里插入图片描述


2.1 初阶用法 ---- 字符串传递

在父组件中 provide 提供变量

文件目录:src/views/monitors/index.vue

<template>
  <!-- 父组件 -->
  <div>
    <Child></Child>
  </div>
</template>

<script>
import Child from "./seed/index";
export default {
  components: {
    Child,
  },
  provide: {
    message: "传给孙组件的值",
  },
  data() {
    return {};
  },
};
</script>

在子组件中,我们不使用任何父组件的信息

文件目录:src/views/monitors/seed/index.vue

<template>
  <!-- 子组件 -->
  <div>
    <el-dialog :visible.sync="centerDialogVisible" width="30%" center>
      <grandson />
    </el-dialog>
  </div>
</template>

<script>
import grandson from "./grandson/index";
export default {
  components: {
    grandson,
  },
  data() {
    return {
      centerDialogVisible: true,
    };
  },
};
</script>

在孙组件中,使用 inject 来注入

文件目录:src/views/monitors/seed/grandson/index.vue

<template>
  <!-- 孙组件 -->
  <div>
    {{message }}
  </div>
</template>

<script>
export default {
  inject: ["message"],
  data() {
    return {};
  },
};
</script>

页面效果

在这里插入图片描述


2.2 中阶用法 ---- 传递data中属性

上面的例子我们是在 provide 中定义的一个字符串,那如果要传 data 里的一个属性呢?这个时候就需要稍微修改一下组件,provide 需要用 returen 的写法。

需要在父组件中修改

文件目录:src/views/monitors/index.vue

<template>
  <!-- 父组件 -->
  <div>
    <Child></Child>
  </div>
</template>

<script>
import Child from "./seed/index";
export default {
  components: {
    Child,
  },
  provide() {
    return {
      message: this.message,
    };
  },
  data() {
    return {
      message: "传给孙组件的值",
    };
  },
};
</script>

子组件和孙组件依旧保持不变。

页面效果

在这里插入图片描述


2.3 高阶用法 ---- 响应式数据

文章开头我们提到了 provideinject 绑定并不是可响应的。 那如何变成响应式的呢,再简单改一下。

还是在父组件中修改

文件目录:src/views/monitors/index.vue

<template>
  <!-- 父组件 -->
  <div>
    <Child></Child>
  </div>
</template>
  
<script>
import Child from "./seed/index";
export default {
  components: {
    Child,
  },
  provide() {
    return {
      message: this.obj,
    };
  },
  data() {
    return {
      obj: {
        num: 0,
      },
    };
  },
  created() {
    setInterval(() => {
      this.obj.num++;
    }, 1000);
  },
};
</script>

子组件依旧不变

孙组件中稍加修改

文件目录:src/views/monitors/seed/grandson/index.vue

<template>
  <!-- 孙组件 -->
  <div>
    {{message.num}}
  </div>
</template>

<script>
export default {
  inject: ["message"],
  data() {
    return {};
  },
};
</script>

页面效果

在这里插入图片描述

注意:

传过去的必须是可监听的对象,其他类型都不行。


2.3.1 传递 this

上面的操作,我们只是取了 data 中的一个对象,当然,你可以直接传一个 this 过去,这样孙组件就会获得爷爷组件的实例对象,且这种方式也是响应式的。

仍然是在父组件中修改

文件目录:src/views/monitors/index.vue

<template>
  <!-- 父组件 -->
  <div>
    <Child></Child>
  </div>
</template>

<script>
import Child from "./seed/index";
export default {
  components: {
    Child,
  },
  provide() {
    return {
      message: this,
    };
  },
  data() {
    return {
      obj: {
        num: 0,
      },
    };
  },
  created() {
    setInterval(() => {
      this.obj.num++;
    }, 1000);
  },
};
</script>

子组件依旧不变

孙组件中再次稍加修改

文件目录:src/views/monitors/seed/grandson/index.vue

<template>
  <!-- 孙组件 -->
  <div>
    {{message.obj.num}}
  </div>
</template>

<script>
export default {
  inject: ["message"],
  data() {
    return {};
  },
};
</script>

页面效果

在这里插入图片描述


小结

在这里插入图片描述
通过一系列的理论+实践,现在我们回过头再来看文章开头的这张图是不是就很清晰了,但是可能有人问了,难道 provide/inject 就没有什么缺点吗?咱们接着往下看。


3、provide/inject 的缺点

大家都知道,在项目中通常追求有清晰的数据流向和合理的组件层级关系,以便于调试和维护,然而 provideinject 支持任意层级都能访问的特性,导致数据追踪比较困难,你压根不知道是哪一个层级声明了 provide,或者不知道哪一个层级或若干个层级使用了 inject,后期容易造成比较大的维护成本。因此,provideinject 在常规应用下并不建议使用,vue 更建议使用 vuex 解决。但是在做组件库开发时,不对 vuex 进行依赖,且不知道用户使用环境的情况下可以很好的使用 provideinject。官方也着重说明 provideinject 主要为高阶插件/组件库提供用例,并不推荐直接用于应用程序代码中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从原理到实战:vue中的provide/inject让你的代码更优美 的相关文章

  • [vue-i18n] Value of key '图标管理' is not a string!

    今天项目运行时报了很多vue i18n esm js a925 14 vue i18n Value of key 图标管理 is not a string 的错 xff1a 解决方案 xff1a 在项目的index js文件中修改配置 xf
  • 996,活着抑或死亡

    就在昨天 xff0c 2021年元旦假期的最后一天 xff0c 网传某大厂多多买菜的23岁小姑娘离开了这个世界 不久之前 xff0c 也有另一大厂的朋友因工作强度太大 xff0c 在字节跳动与心脏跳动中选择了后者 还有更戏剧化的新闻是刚因大

随机推荐

  • 2018年度总结

    2019新的一年到了 xff0c 又是一年到收获的季节 xff0c 在去年自己见证了师哥师姐的收获 xff0c 支付宝的出了自己的消费清单 xff0c 自己给自己一份2018年度成长清单 计算机 今年开始学习java xff0c 从开始的不
  • 模糊查询

    lt select id 61 34 findByUserIdMonthAttend 34 resultMap 61 34 BaseResultMap 34 gt SELECT lt include refid 61 34 Base Col
  • 字符串连接

    StringBuilder StringBuffer String三者区别 1 运行速度 xff0c 在这方面运行速度快慢为 xff1a StringBuilder gt StringBuffer gt String String最慢的原因
  • 集合

    Java集合类存放于 java util 包中 xff0c 是一个用来存放对象的容器 集合只能存放对象 比如你存一个 int 型数据 1放入集合中 xff0c 其实它是自动转换成 Integer 类后存入的 xff0c Java中每一种基本
  • 事务

    事务必须服从ISO IEC所制定的ACID原则 ACID是原子性 xff08 atomicity xff09 一致性 xff08 consistency xff09 隔离性 xff08 isolation xff09 和持久性 xff08
  • vue select 获取value和lable

    vue select控件在选择时需要把id和name两个值都获取到 xff0c 实现方案如下 xff1a select控件代码 lt FormItem label 61 34 物资类型 xff1a 34 prop 61 34 supplyT
  • vue中render函数子组件调用父组件方法

    父组件render函数内容 return h swichbutton swichbutton为子组件 props row params row valveState props声明给子组件传递的参数 xff0c 子组件通过以下方式接收 pr
  • Couldn't find preset "es2015" relative to directory

    修改 babelrc文件内容如下 xff0c 运行后报错 Module build failed Error Couldn t find preset es2015 relative to directory 34 presets 34 3
  • vue运行同时被localhost和ip地址访问

    在index js文件下修改host内容 xff0c localhost改为本机ip host 39 192 168 X XX 39 can be overwritten by process env HOST port 8080 can
  • AppData\Roaming\npm-cache\_logs

    npm install报如下错误 xff1a npm ERR code ELIFECYCLE npm ERR errno 1 npm ERR bhwechat 64 1 0 0 dev 96 webpack dev server inlin
  • 你和高手的差距,就在一念之间

    我一直做软件开发和技术管理工作 xff0c 虽然在做联合创始人期间也参与2B的市场销售运营等众多事情 xff0c 但2C的电商卖货这件事从未体验过 想起小学时学的小马过河的故事 xff0c 要想知道怎么做 xff0c 不能只听别人的说法 x
  • 动态IF语句拼接sql语句

    动态IF语句拼接sql语句 lt 列表 正式 非居民 gt lt select id 61 34 listFormatNodWeller 34 resultType 61 34 com jczb binhe oa model Nodwell
  • swagger基本注解

    与使用Swagger核心注释注释模型类以提供其他元数据相同 xff0c 可以注释控制器及其方法和方法参数 64 Api描述了整个控制器 64 ApiOperation用于方法级别的描述 64 ApiParam用于方法参数 64 RestCo
  • sql语句foreach

    lt 查询 新户水表信息 gt lt select id 61 34 getWaterMeterStartByMeterCodeNew 34 parameterType 61 34 com jczb binhe oa model Water
  • groupconcat函数

    比如select group concat name MySQL中group concat函数 语法如下 xff1a group concat DISTINCT 要连接的字段 Order BY ASC DESC 排序字段 Separator
  • echart百度地图取消点击事件

    在下载的nodemodule包中修改代码 var bmap 61 bmapModel bmap 61 new BMap Map bmapRoot enableMapClick false
  • JavaEE规范

    十三个规范为 xff1a JDBC xff08 java Database Connectivity xff09 xff1a JDBC API为访问不同的数据库提供了一种统一的途径 JNDI Java Name and Directory
  • Java反射

    什么时候用 Java程序中许多对象在运行时出现两种类型 xff1a 编译时类型和运行时类型 xff0c 例如Person p 61 New Student 这时生成的p变量的编译时类型为Person xff0c 运行时类型为Student
  • css3 animation 实现帧动画

    先上代码 xff1a lt DOCTYPE html gt lt html gt lt head gt lt title gt lt title gt lt style gt ani container width 125px height
  • 从原理到实战:vue中的provide/inject让你的代码更优美

    前言 关于 vue 中的 provide inject 这一主题 xff0c 它可以被看作是一种高级的依赖注入机制 xff0c 允许跨层级组件实现状态共享 xff0c 从而提高代码的可维护性和扩展性 在这篇文章中 xff0c 我将从原理到实