返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Vue3全局组件通信之provide / inject详解
  • 282
分享到

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

Vue3全局组件通信Vue3全局组件Vue3组件通信 2023-03-14 14:03:04 282人浏览 薄情痞子
摘要

目录1、前言2、provide / inject3、发起 provide4、接收 inject5、响应性数据的传递与接收6、引用类型的传递与接收 (针对非响应性数据的处理)7、基本类

1、前言

顾名思义,爷孙组件是比 父子组件通信 要更深层次的引用关系(也有称之为 “隔代组件”):

C组件引入到B组件里,B组件引入到A组件里渲染,此时A是C的爷爷级别(可能还有更多层级关系),如果你用 props ,只能一级一级传递下去,那就太繁琐了,因此我们需要更直接的通信方式。

他们之间的关系如下,Grandson.Vue 并非直接挂载在 Grandfather.vue 下面,他们之间还隔着至少一个 Son.vue (可能有多个):

Grandfather.vue
└─Son.vue
  └─Grandson.vue

???
因为上下级的关系的一致性,爷孙组件通信的方案也适用于 父子组件通信 ,只需要把爷孙关系换成父子关系即可。

2、provide / inject

这个特性有两个部分:Grandfather.vue 有一个 provide 选项来提供数据,Grandson.vue 有一个 inject 选项来开始使用这些数据。

  • Grandfather.vue 通过 provide 向 Grandson.vue 传值(可包含定义好的函数)
  • Grandson.vue 通过 inject 向 Grandfather.vue 触发爷爷组件的事件执行

???
无论组件层次结构有多深,发起 provide 的组件都可以作为其所有下级组件的依赖提供者
这一部分的内容变化都特别大,但使用起来其实也很简单,不用慌,也有相同的地方:

  • 父组件不需要知道哪些子组件使用它 provide 的 property
  • 子组件不需要知道 inject property 来自哪里

另外,要切记一点就是:provide 和 inject 绑定并不是可响应的。这是刻意为之的,但如果传入了一个可监听的对象,那么其对象的 property 还是可响应的。

3、发起 provide

我们先来回顾一下 2.x 的用法:

export default {
  // 定义好数据
  data () {
    return {
      tags: [ '中餐', '粤菜', '烧腊' ]
    }
  },
  // provide出去
  provide () {
    return {
      tags: this.tags
    }
  }
}

旧版的 provide 用法和 data 类似,都是配置为一个返回对象的函数。
3.x 的新版 provide, 和 2.x 的用法区别比较大。

???
在 3.x , provide 需要导入并在 setup 里启用,并且现在是一个全新的方法。
每次要 provide 一个数据的时候,就要单独调用一次。
每次调用的时候,都需要传入 2 个参数:

参数类型说明
keystring数据的名称
valueany数据的值

来看一下如何创建一个 provide:

// 记得导入provide
import { defineComponent, provide } from 'vue'

export default defineComponent({
  // ...
  setup () {
    // 定义好数据
    const msg: string = 'Hello World!';

    // provide出去
    provide('msg', msg);
  }
})

操作非常简单对吧,但需要注意的是,provide 不是响应式的,如果你要使其具备响应性,你需要传入响应式数据

4、接收 inject

也是先来回顾一下 2.x 的用法:

export default {
  inject: ['tags'],
  mounted () {
    console.log(this.tags);
  }
}

旧版的 inject 用法和 props 类似,3.x 的新版 inject, 和 2.x 的用法区别也是比较大。

???
在 3.x, inject 和 provide 一样,也是需要先导入然后在 setup 里启用,也是一个全新的方法。
每次要 inject 一个数据的时候,就要单独调用一次。
每次调用的时候,只需要传入 1 个参数:

参数类型说明
keystring与provide对应的数据名称
// 记得导入inject
import { defineComponent, inject } from 'vue'

export default defineComponent({
  // ...
  setup () {
    const msg: string = inject('msg') || '';
  }
})

也是很简单(写 TS 的话,由于 inject 到的值可能是 undefined,所以要么加个 undefined 类型,要么给变量设置一个空的默认值)。

5、响应性数据的传递与接收

之所以要单独拿出来说, 是因为变化真的很大

在前面我们已经知道,provide 和 inject 本身不可响应,但是并非完全不能够拿到响应的结果,只需要我们传入的数据具备响应性,它依然能够提供响应支持。

我们以 ref 和 Reactive 为例,来看看应该怎么发起 provide 和接收 inject。

先在 Grandfather.vue 里 provide 数据:

export default defineComponent({
  // ...
  setup () {
    // provide一个ref
    const msg = ref<string>('Hello World!');
    provide('msg', msg);

    // provide一个reactive
    const userInfo: Member = reactive({
      id: 1,
      name: 'Petter'
    });
    provide('userInfo', userInfo);

    // 2s 后更新数据
    setTimeout(() => {
      // 修改消息内容
      msg.value = 'Hi World!';

      // 修改用户名
      userInfo.name = 'Tom';
    }, 2000);
  }
})

在 Grandsun.vue 里 inject 拿到数据:

export default defineComponent({
  setup () {
    // 获取数据
    const msg = inject('msg');
    const userInfo = inject('userInfo');

    // 打印刚刚拿到的数据
    console.log(msg);
    console.log(userInfo);

    // 因为 2s 后数据会变,我们 3s 后再看下,可以争取拿到新的数据
    setTimeout(() => {
      console.log(msg);
      console.log(userInfo);
    }, 3000);

    // 响应式数据还可以直接给 template 使用,会实时更新
    return {
      msg,
      userInfo
    }
  }
})

非常简单,非常方便!!!

???
响应式的数据 provide 出去,在子孙组件拿到的也是响应式的,并且可以如同自身定义的响应式变量一样,直接 return 给 template 使用,一旦数据有变化,视图也会立即更新。

但上面这句话有效的前提是,不破坏数据的响应性,比如 ref 变量,你需要完整的传入,而不能只传入它的 value,对于 reactive 也是同理,不能直接解构去破坏原本的响应性

切记!切记!!!

6、引用类型的传递与接收 (针对非响应性数据的处理)

provide 和 inject 并不是可响应的,这是官方的故意设计,但是由于引用类型的特殊性,在子孙组件拿到了数据之后,他们的属性还是可以正常的响应变化。

先在 Grandfather.vue 里 provide 数据:

export default defineComponent({
  // ...
  setup () {
    // provide 一个数组
    const tags: string[] = [ '中餐', '粤菜', '烧腊' ];
    provide('tags', tags);

    // provide 一个对象
    const userInfo: Member = {
      id: 1,
      name: 'Petter'
    };
    provide('userInfo', userInfo);

    // 2s 后更新数据
    setTimeout(() => {
      // 增加tags的长度
      tags.push('叉烧');

      // 修改userInfo的属性值
      userInfo.name = 'Tom';
    }, 2000);
  }
})

在 Grandsun.vue 里 inject 拿到数据:

export default defineComponent({
  setup () {
    // 获取数据
    const tags: string[] = inject('tags') || [];
    const userInfo: Member = inject('userInfo') || {
      id: 0,
      name: ''
    };

    // 打印刚刚拿到的数据
    console.log(tags);
    console.log(tags.length);
    console.log(userInfo);

    // 因为 2s 后数据会变,我们 3s 后再看下,能够看到已经是更新后的数据了
    setTimeout(() => {
      console.log(tags);
      console.log(tags.length);
      console.log(userInfo);
    }, 3000);
  }
})

export default defineComponent({
  setup () {
    // 获取数据
    const tags: string[] = inject('tags') || [];
    const userInfo: Member = inject('userInfo') || {
      id: 0,
      name: ''
    };

    // 打印刚刚拿到的数据
    console.log(tags);
    console.log(tags.length);
    console.log(userInfo);

    // 因为 2s 后数据会变,我们 3s 后再看下,能够看到已经是更新后的数据了
    setTimeout(() => {
      console.log(tags);
      console.log(tags.length);
      console.log(userInfo);
    }, 3000);
  }
})

???
引用类型的数据,拿到后可以直接用,属性的值更新后,子孙组件也会被更新。
但是!!!由于不具备真正的响应性,return 给模板使用依然不会更新视图,如果涉及到视图的数据,请依然使用 响应式 API 。

7、基本类型的传递与接收 (针对非响应性数据的处理)

基本数据类型被直接 provide 出去后,再怎么修改,都无法更新下去,子孙组件拿到的永远是第一次的那个值。

先在 Grandfather.vue 里 provide 数据:

export default defineComponent({
  // ...
  setup () {
    // provide 一个数组的长度
    const tags: string[] = [ '中餐', '粤菜', '烧腊' ];
    provide('tagsCount', tags.length);

    // provide 一个字符串
    let name: string = 'Petter';
    provide('name', name);

    // 2s 后更新数据
    setTimeout(() => {
      // tagsCount 在 Grandson 那边依然是 3
      tags.push('叉烧');

      // name 在 Grandson 那边依然是 Petter
      name = 'Tom';
    }, 2000);
  }
})

在 Grandsun.vue 里 inject 拿到数据:

export default defineComponent({
  setup () {
    // 获取数据
    const name: string = inject('name') || '';
    const tagsCount: number = inject('tagsCount') || 0;

    // 打印刚刚拿到的数据
    console.log(name);
    console.log(tagsCount);

    // 因为 2s 后数据会变,我们 3s 后再看下
    setTimeout(() => {
      // 依然是 Petter
      console.log(name);

      // 依然是 3
      console.log(tagsCount);
    }, 3000);
  }
})

很失望,并没有变化。

???
那么是否一定要定义成响应式数据或者引用类型数据呢?

当然不是,我们在 provide 的时候,也可以稍作修改,让它能够同步更新下去。

先在 Grandfather.vue 里 provide 数据:

export default defineComponent({
  // ...
  setup () {
    // provide 一个数组的长度
    const tags: string[] = [ '中餐', '粤菜', '烧腊' ];
    provide('tagsCount', (): number => {
      return tags.length;
    });

    // provide 字符串
    let name: string = 'Petter';
    provide('name', (): string => {
      return name;
    });

    // 2s 后更新数据
    setTimeout(() => {
      // tagsCount 现在可以正常拿到 4 了
      tags.push('叉烧');

      // name 现在可以正常拿到 Tom 了
      name = 'Tom';
    }, 2000);
  }
})

再来 Grandsun.vue 里修改一下 inject 的方式,看看这次拿到的数据:

export default defineComponent({
  setup () {
    // 获取数据
    const tagsCount: any = inject('tagsCount');
    const name: any = inject('name');

    // 打印刚刚拿到的数据
    console.log(tagsCount());
    console.log(name());

    // 因为 2s 后数据会变,我们 3s 后再看下
    setTimeout(() => {
      // 现在可以正确得到 4
      console.log(tagsCount());

      // 现在可以正确得到 Tom
      console.log(name());
    }, 3000);
  }
})

这次可以正确拿到数据了,看出这2次的写法有什么区别了吗?

???
基本数据类型,需要 provide 一个函数,将其 return 出去给子孙组件用,这样子孙组件每次拿到的数据才会是新的。
但由于不具备响应性,所以子孙组件每次都需要重新通过执行 inject 得到的函数才能拿到最新的数据。

按我个人习惯来说,使用起来挺别扭的,能不用就不用……

由于不具备真正的响应性,return 给模板使用依然不会更新视图,如果涉及到视图的数据,请依然使用 响应式 API 。

到此这篇关于vue3全局组件通信之provide / inject的文章就介绍到这了,更多相关Vue3全局组件通信内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Vue3全局组件通信之provide / inject详解

本文链接: https://lsjlt.com/news/199766.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Vue3全局组件通信之provide / inject详解
    目录1、前言2、provide / inject3、发起 provide4、接收 inject5、响应性数据的传递与接收6、引用类型的传递与接收 (针对非响应性数据的处理)7、基本类...
    99+
    2023-03-14
    Vue3全局组件通信 Vue3全局组件 Vue3组件通信
  • Vue3全局组件通信之provide/inject源码分析
    1、前言顾名思义,爷孙组件是比 父子组件通信 要更深层次的引用关系(也有称之为 “隔代组件”):C组件引入到B组件里,B组件引入到A组件里渲染,此时A是C的爷爷级别(可能还有更多层级关系),如果你用 props ,只能一级一级传递下去,那就...
    99+
    2023-05-14
    Vue3 provide inject
  • Vue3全局组件通信之provide/inject怎么使用
    本篇内容介绍了“Vue3全局组件通信之provide/inject怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、前言顾名思义,爷...
    99+
    2023-07-06
  • vue3-组合式api-provide/inject详解
    目录一、父组件二、子组件三、孙组件四、运行项目界面效果如下Vue3:组合式API-依赖注入(provide()、inject())1.provide() 2.inject(...
    99+
    2022-11-13
    vue3组合式api vue3组合式api-provide/inject vue3 provide vue依赖注入
  • vue3 非父子组件通信详解
    目录第一种方法App.vueHome.vueHomeContent.vue数据的响应式修改响应式Property总结业务场景是,不是父子组件实现通信 文件目录 第一种方法 Ap...
    99+
    2024-04-02
  • VUE3学习教程之全局组件和局部组件
    目录1. 概述2. 全局组件2.1 不使用组件的写法2.2 使用组件2.3 组件中包含变量2.4 组件的复用2.5 组件中使用组件2.6 总结3. 局部组件3.1 局部组件的使用3....
    99+
    2024-04-02
  • react之组件通信详解
    目录父组件与子组件通信子组件与父组件通信跨组件通信祖先子孙兄弟节点通信总结父组件与子组件通信 父组件将自己的状态传递给子组件,子组件当做属性来接收,当父组件更改自己状态的时...
    99+
    2024-04-02
  • Vue3组件间的通信方式详解
    目录1、父子组件通信1.1 defineProps1.2 provide/inject2.子父组件通信2.1 defineEmits2.2 v-model:xxx+emit在写 vu...
    99+
    2023-05-17
    Vue3组件通信 Vue3组件通信方式
  • 详解Vue3的七种组件通信方式
    目录写在前面举一个栗子Props方式emit方式v-model方式refs方式provide/inject方式事件总线状态管理工具写在前面 本篇文章是全部采用的<script ...
    99+
    2024-04-02
  • Vue3的7种种组件通信详情
    目录1、Vue3 组件通信方式2、Vue3 通信使用写法2.1 props2.2 $emit2.3 expose / ref2.4 attrs2.5 v-model2.6 provi...
    99+
    2024-04-02
  • 详解Vue全局组件的挂载之实现弹窗组件
    目录vue组件挂载类型组件挂载代码示例1.vue.extend()方法2.render函数挂载vue组件挂载类型 vue中组件的挂载分为两种类型: vue.extend() rend...
    99+
    2022-11-13
    Vue组件挂载 弹窗 Vue组件挂载 Vue弹窗组件 Vue 弹窗
  • 详解React中组件之间通信的方式
    一、是什么 我们将组件间通信可以拆分为两个词: 组件 通信 回顾Vue系列的文章,组件是vue中最强大的功能之一,同样组件化是React的核心思想 相比vue,...
    99+
    2024-04-02
  • Vue组件之间四种通信方式详解
    目录前言父子组件通信​父组件与子孙组件的通信​父组件获取子组件数据​无需考虑组件关系的通信​前言 vue 框架提供了前端开发组件的思想,可以通过组件来组合成一个完整的页面,都是随着组...
    99+
    2024-04-02
  • Vue3组件挂载之创建组件实例详解
    目录前情提要mountComponent创建组件实例总结前情提要 上文我们讲解了执行createApp(App).mount('#root')中的mount函数,我们...
    99+
    2022-11-13
    Vue3 组件挂载创建实例 Vue3 组件挂载
  • Vue组件之间的通信方式详细讲解
    目录前言一、父级传数据给子级1、传输固定的具体数据2、动态语法3、子组件调用父组件二、子级传数据给父级1、使用自定义事件2、$refs的使用3、同级别组价以及任意组件之间的数据传递前...
    99+
    2024-04-02
  • angular父子组件通信详解
    目录用到的api简单的例子person.ts父组件子组件效果总结用到的api Input - 子组件中定义可接受的属性,可以用来父组件给子组件传递数据 Output - 子组件中定义...
    99+
    2024-04-02
  • vue组件间通信全面讲解
    目录前言组件介绍一、父传子1. 父组件通过 props 传递数据给子组件2. 定义props的类型和默认值二、子传父子组件通过 $emit 传递数据给父组件三、非父子组件间数据传递1...
    99+
    2024-04-02
  • Vue非父子组件之间的通信方式详解
    目录非父子组件的通信1.Provide和Inject1.1基本使用1.2处理响应式数据(了解)2.全局事件总线总结非父子组件的通信 此篇讲解的是, 在学习状态管理之前, 非父子间通信...
    99+
    2024-04-02
  • Vue组件的通信方式详解
    目录组件间通信的概念组件间通信解决了什么?组件间通信的分类组件间通信的方案props传递数据$emit 触发自定义事件refEventBus$parent 或 $root$attrs...
    99+
    2023-05-15
    Vue组件间的通信方式 Vue组件间通信
  • 详解React hooks组件通信方法
    目录一、前言二、父子组件通信1)父组件传值给子组件2)子组件传值给父组件3)跨组件传值(父传孙子组件)一、前言 组件通信是React中的一个重要的知识点,下面列举一下 react h...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作