Vue中provide、inject详解以及使用教程

目录
  • Vue中 常见的组件通信方式可分为三类
  • 1. provide / inject 简介
  • 2. provide / inject 使用方法
  • 3. 总结
  • 总结
  • 传送门:Vue中 子组件向父组件传值 及 .sync 修饰符 详解
  • 传送门:Vue中 状态管理器(vuex)详解及应用场景
  • 传送门:Vue中 $ attrs、$ listeners 详解及使用
  • 传送门:Vue中 事件总线(eventBus)详解及使用
  • 传送门:Vue 2.x 官方文档 provide / inject 说明

Vue中 常见的组件通信方式可分为三类

父子通信

父向子传递数据是通过 props,子向父是通过 events($emit);
通过父链 / 子链也可以通信($parent / $children);
ref 也可以访问组件实例;
provide / inject;
$attrs/$listeners;

兄弟通信

Bus;
Vuex;

跨级通信

Bus;
Vuex;
provide / inject、
$attrs / $listeners、

1. provide / inject 简介

类型

provide:Object | () => Object
inject: Array<string> | { [key: string]: string | Symbol | Object }

详细

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效。
如果你熟悉 React,这与 React 的上下文特性很相似。

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的 property。
在该对象中可使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作。

inject 选项应该是:
  一个字符串数组,或
  一个对象,对象的 key 是本地的绑定名,value 是:
      在可用的注入内容中搜索用的 key (字符串或 Symbol),或
      一个对象,该对象的:
         from property 是在可用的注入内容中搜索用的 key (字符串或 Symbol)
         default property 是降级情况下使用的 value

2. provide / inject 使用方法

祖组件

<template>
  <div>
    <button @click="changeMsg">祖组件触发</button>
    <h1>祖组件</h1>
    <parent></parent>
  </div>
</template>

<script>
import parent from './parent.vue';
export default {
  data(){
    return{
      obj:{
        name:'JavaScript',
      },
      developer:'布兰登·艾奇',
      year:1995,
      update:'2021年06月',
    }
  },
  provide(){
    return {
      obj: this.obj, // 方式1.传入一个可监听的对象
      developerFn:() => this.developer, // 方式2.通过 computed 来计算注入的值
      year: this.year, // 方式3.直接传值
      app: this, // 4. 提供祖先组件的实例 缺点:实例上挂载很多没有必要的东西 比如:props,methods。
    }
  },
  components: {
    parent,
  },
  methods:{
    changeMsg(){
      this.obj.name = 'Vue';
      this.developer = '尤雨溪';
      this.year = 2014;
      this.update = '2021年6月7日';
    },
  },
}
</script>

父组件

<template>
  <div class="wrap">
    <h4>子组件(只做中转)</h4>
    <child></child>
  </div>
</template>

<script>
import child from './child.vue';
export default {
  components:{
    child,
  },
}
</script>

孙组件

<template>
  <div>
    <h5>孙组件</h5>
    <span>名称:{{obj.name}}</span> |
    <span>作者:{{developer}}</span> |
    <span>诞生于:{{year}}</span> |
    <span>最后更新于:{{this.app.update}}</span>
  </div>
</template>

<script>
export default {
  computed:{
    developer(){
      return this.developerFn()
    }
  },
  inject:['obj','developerFn','year','app'],
}
</script>

未点击按钮,原有状态

当点击按钮触发 changeMsg 方法后,效果如下:

对比一下前后差异:无论点击多少次,孙组件中的诞生于 year 字段永远都是1995 并不会发生变化,通过 方式1、方式2、方式4传值是可以响应的。

正是官网所提到的:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。

在孙组件中修改祖组件传递过来的值(方式1、方式4),发现对应的祖组件中的值也发生了变化。

祖组件

<template>
  <div>
    <h1>祖组件</h1>
    <span>名称:{{obj.name}}</span> |
    <span>最后更新于:{{update}}</span>
    <parent></parent>
  </div>
</template>

<script>
import parent from './parent.vue';
export default {
  data(){
    return{
      obj:{
        name:'JavaScript',
      },
      update:'2021年06月',
    }
  },
  provide(){
    return {
      obj: this.obj,
      app: this,
    }
  },
  components: {
    parent,
  },
}
</script>

父组件不变

孙组件

<template>
  <div>
    <button @click="changeMsg">孙组件触发</button>
    <h3>孙组件</h3>
    <span>名称:{{obj.name}}</span> |
    <span>最后更新于:{{this.app.update}}</span>
  </div>
</template>

<script>
export default {
  inject:['obj','app'],
  methods: {
    changeMsg(){
      this.obj.name = 'React';
      this.app.update = '2020年10月';
    }
  },
}
</script>

未点击按钮,原有状态

当点击按钮触发 changeMsg 方法后,效果如下:

3. 总结

慎用 provide / inject

既然 provide/inject 如此好用,那么,为什么 Vue 官方还要推荐我们使用 Vuex,而不是用原生的 API 呢?
前面提到过,Vuex 和 provide/inject 最大的区别:Vuex 中的全局状态的每次修改是可以追踪回溯的,而 provide/inject 中变量的修改是无法控制的。换句话说,不知道是哪个组件修改了这个全局状态。
Vue 的设计理念借鉴了 React 中的单向数据流原则(虽然有 sync 这种破坏单向数据流的家伙),而 provide/inject 明显破坏了单向数据流原则。试想,如果有多个后代组件同时依赖于一个祖先组件提供的状态,那么只要有一个组件修改了该状态,那么所有组件都会受到影响。这一方面增加了耦合度,另一方面,使得数据变化不可控。如果在多人协作开发中,这将成为一个噩梦。

在这里,总结了使用 provide/inject 做全局状态管理的原则:

  • 多人协作时,做好作用域隔离;
  • 尽量使用一次性数据作为全局状态

看起来,使用 provide / inject 做全局状态管理好像很危险,那么有没有 provide / inject 更好的使用方式呢?
当然有,那就是使用 provide / inject 编写组件。

使用 provide / inject 编写组件

使用 provide/inject 做组件开发,是 Vue 官方文档中提倡的一种做法。

以我们比较熟悉的 elementUI 来举例:

在 elementUI 中有 Button(按钮)组件,当在 Form(表单)组件中使用时,它的尺寸会同时受到外层的 FormItem 组件以及更外层的 Form 组件中的 size 属性的影响。

如果是常规方案,我们可以通过 props 从 Form 开始,一层层往下传递属性值。看起来只需要传递传递两层即可,还可以接受。但是,Form 的下一层组件不一定是 FormItem,FormItem 的下一层组件不一定是 Button,它们之间还可以嵌套其他组件,也就是说,层级关系不确定。如果使用 props,我们写的组件会出现强耦合的情况。

provide/inject 可以完美的解决这个问题,只需要向后代注入组件本身(上下文),后代组件中可以无视层级任意访问祖先组件中的状态。

部分源码如下:

export default {
  name: 'ElButton',
  // 通过 inject 获取 elForm 以及 elFormItem 这两个组件
  inject: {
    elForm: {
      default: ''
    },
    elFormItem: {
      default: ''
    }
  },
  // ...
  computed: {
    _elFormItemSize() {
      return (this.elFormItem || {}).elFormItemSize;
    },
    buttonSize() {
      return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
    },
    //...
  },
  // ...
};

总结

到此这篇关于Vue中provide、inject详解及使用的文章就介绍到这了,更多相关Vue provide、inject详解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • vue3中 provide 和 inject 用法及原理

    前言: 在父子组件传递数据时,通常使用的是 props 和 emit,父传子时,使用的是 props,如果是父组件传孙组件时,就需要先传给子组件,子组件再传给孙组件,如果多个子组件或多个孙组件使用时,就需要传很多次,会很麻烦. 像这种情况,可以使用 provide 和 inject 解决这种问题,不论组件嵌套多深,父组件都可以为所有子组件或孙组件提供数据,父组件使用 provide 提供数据,子组件或孙组件 inject 注入数据.同时兄弟组件之间传值更方便. 一.Vue2 的 provide

  • 聊聊Vue中provide/inject的应用详解

    众所周知,在组件式开发中,最大的痛点就在于组件之间的通信.在 Vue 中,Vue 提供了各种各样的组件通信方式,从基础的 props/$emit 到用于兄弟组件通信的 EventBus,再到用于全局数据管理的 Vuex. 在这么多的组件通信方式中,provide/inject 显得十分阿卡林(毫无存在感).但是,其实 provide/inject 也有它们的用武之地.今天,我们就来聊聊 Vue 中 provide/inject 的应用. 何为 provide/inject provide/inj

  • vue中的provide/inject的学习使用

    前言 最近在看element-ui的源码,发现了一个这样的属性:inject.遂查看官网provider/inject provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量. 需要注意的是这里不论子组件有多深,只要调用了inject那么就可以注入provider中的数据.而不是局限于只能从当前父组件的prop属性来获取数据. 下面我们来验证下猜想: first:定义一个parent component <template

  • vue 解决provide和inject响应的问题

    官网上说provide 和 inject 绑定并不是可响应的.这是刻意为之的.然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的. provide: Object | () => Object(一个对象或返回一个对象的函数) inject: Array | { [key: string]: string | Symbol | Object }(一个字符串数组,或一个对象,对象的 key 是本地的绑定名) 要实现父子组件响应,父组件传递的数据类型必须是对象Object,子组件接收的数

  • 浅析vue中的provide / inject 有什么用处

    1.前言 vue的父子组件通信用什么? :prop和$emit的组合. 如果是爷孙组件呢? :那么就要用父组件来转发数据和事件了. 如果是太爷爷和孙子组件呢? :当然是vuex啦 emmm 好的,没我啥事了,我这就走. 不行,我还能再挣扎一会儿!肯定有一部分兄弟做的项目比较小,组件通信的情况不是很多,懒得引入vuex,那么provide/inject就是爷孙(不限于爷孙/父子,中间隔了多少级都可以)通信问题的最好解决方案啦! 2.官方文档抄过来的介绍 这对选项需要一起使用,以允许一个祖先组件向其

  • vue中使用[provide/inject]实现页面reload的方法

    在vue中实现页面刷新有不同的方法: 如:this.$router.go(0),location.reload()等,但是或多或少会存在问题,如页面会一闪等 所以建议使用[provide/inject]实现刷新 该方法t简单的来说就是在父组件中 1.设置provider 2.然后在子组件中通过inject调用 3.在需要执行的地方直接调用方法即可 总结 以上所述是小编给大家介绍的vue中使用[provide/inject]实现页面reload的方法,希望对大家有所帮助,如果大家有任何疑问请给我留

  • 解析vue的provide和inject使用方法及其原理

    首先来谈谈我们为什么要使用provide/inject呢?对于爷爷和孙子组件之间,甚至太爷爷组件与孙子组件通信我们用vuex不就ok了. 那事实的确如此,但是,请听我说但是,有时候你项目比较小甚至组件通信的场景很少的,那么你引入vuex就为了那么几个通信传参是不是很浪费啊.有人也可能会想到使用$parent获取父组件实例,来获取data/methods,这种两层就还好,那多层呢,组件嵌套很深的话,你怎么弄?写个函数把$parent再封装一下.那不是很麻烦吗,现成的你不用非要曲线救国.哈哈-扯远了

  • vue中provide inject的响应式监听解决方案

    目录 provide inject的响应式监听解决 vue监听赋值及provide与inject provide inject的响应式监听解决 提示:provide 和 inject 绑定并不是可响应的.这是刻意为之的.然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的. 所以传值传对象即可 provide(){     return {       provObj: {         uuidList:{}       }     }   }, this._provided.p

  • Vue中props的详解

    看一下官方文档: 组件实例的作用域是孤立的.这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据.父组件的数据需要通过 prop 才能下发到子组件中. 也就是props是子组件访问父组件数据的唯一接口. 详细一点解释就是: 一个组件可以直接在模板里面渲染data里面的数据(双大括号). 子组件不能直接在模板里面渲染父元素的数据. 如果子组件想要引用父元素的数据,那么就在prop里面声明一个变量(比如a),这个变量就可以引用父元素的数据.然后在模板里渲染这个变量(前面的a),这时候渲染

  • vue中组件通信详解(父子组件, 爷孙组件, 兄弟组件)

    vue中我们常常用到组件. 那么组件总体可以分为如下的几种关系. 父子组件, 爷孙组件, 兄弟组件. 这几种组件之间是如何通信的呢? 父子组件通信 根据vue中的文档可知, 组件的props属性用于接收父组件传递的信息. 而子组件想要向父组件传递信息, 可以使用$emit事件. 我们定义两个组件, 一个为父组件名为father, 另外一个为子组件child. 子组件通过props属性接收父组件传递的值, 这个值为fname, 是父组件的名字. 点击子组件的按钮, 触发toFather事件, 向父

  • Vue中provide、inject详解以及使用教程

    目录 Vue中 常见的组件通信方式可分为三类 1. provide / inject 简介 2. provide / inject 使用方法 3. 总结 总结 传送门:Vue中 子组件向父组件传值 及 .sync 修饰符 详解 传送门:Vue中 状态管理器(vuex)详解及应用场景 传送门:Vue中 $ attrs.$ listeners 详解及使用 传送门:Vue中 事件总线(eventBus)详解及使用 传送门:Vue 2.x 官方文档 provide / inject 说明 Vue中 常见

  • Vue3全局组件通信之provide / inject详解

    目录 1.前言 2.provide / inject 3.发起 provide 4.接收 inject 5.响应性数据的传递与接收 6.引用类型的传递与接收 (针对非响应性数据的处理) 7.基本类型的传递与接收 (针对非响应性数据的处理) 1.前言 顾名思义,爷孙组件是比 父子组件通信 要更深层次的引用关系(也有称之为 “隔代组件”): C组件引入到B组件里,B组件引入到A组件里渲染,此时A是C的爷爷级别(可能还有更多层级关系),如果你用 props ,只能一级一级传递下去,那就太繁琐了,因此我

  • 微信jssdk逻辑在vue中的运用详解

    微信 jssdk 在 vue 中的简单使用 import wx from 'weixin-js-sdk'; wx.config({ debug: true, appId: '', timestamp: , nonceStr: '', signature: '', jsApiList: [] }); wx.ready(() => { // do something... }); wx.error((err) => { // do something... }); 以上是微信官方给出的示例代码,但

  • 如何正确理解vue中的key详解

    就目前所了解的情况,key的作用有以下这些. v-for遍历时,用id,uuid之类作为key,唯一标识节点加速虚拟DOM渲染 响应式系统没有监听到的数据,用+new Date()生成的时间戳作为key,手动强制触发重新渲染 场景一大同小异司空见惯,场景二是下面这样的: <div :key="rerender"> <span>Hello Vue.js !</span> <complexComponent :propObj="propO

  • vue中的插槽详解

    vue中代码的复用, 为我们提供了 mixnis. 模板的复用, 为我们提供了 插槽( slot ) 插槽的分类 默认插槽 具名插槽 作用域插槽 当我们的组件中 我们只需要插入一个 html 标签的时候, 就使用默认插槽就可以了, 如果有多个, 我们就要给第一个 插槽取一个名字, 来决定到底插入哪一个插槽 当我们的插槽中要使用组件中的数据的时候, 就可能会用到作用域插槽 下面展示一下, 默认插槽的用法 使用时 以上就是默认插槽的使用 具名插槽, 也就是说我们在组件中定一个 多个 slot , 为

  • vue中$set用法详解

    目录 1.为什么要用set? 2.set用法 3.什么时候使用set? 4.文档地址 摘要:地址没有改变,vue就监测不到数据变化.这个时候,双向绑定就失效了. 想了解有关JS堆栈的知识?请点击这里. 1.为什么要用set? 在vue中,并不是任何时候数据都是双向绑定的.在官方文档中,有这样一段话,如下: 从文档得知,当数据没有被双向绑定的时候,我们就需要使用set了 2.set用法 解决数据没有被双向绑定我们可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名. -

随机推荐