首页 > 其他分享 >【转载】Vue Provide / Inject 详细介绍(跨组件通信、响应式变化、版本变化)

【转载】Vue Provide / Inject 详细介绍(跨组件通信、响应式变化、版本变化)

时间:2023-09-20 23:11:26浏览次数:38  
标签:Vue name Provide provide vue inject 组件 import Inject

版权声明:本文为CSDN博主「前端不释卷leo」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_41809113/article/details/122071958

 

一、背景

通常,当我们需要从父组件向子组件传递数据时,我们使用 props。想象一下这样的结构:有一些深度嵌套的组件,而深层的子组件只需要父组件的部分内容。在这种情况下,如果仍然将 prop 沿着组件链逐级传递下去,可能会很麻烦。
对于这种情况,我们可以使用一对 provide 和 inject。无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。

 

二、vue2中使用

1、基本用法

假设有一个组件A,A组件引入B组件(A为B的父组件) ,B组件引入C组件(B为C的父组件),即A为C的祖先组件,此时二者可以使用provide / inject进行通信。

A.vue

<template>
  <div>
    <B></B>
  </div>
</template>
 
<script>
import B from "./B.vue";
export default {
  name: "A",
  components: {
    B
  },
};
</script>

 

B.vue

<template>
  <div>
    <C></C>
  </div>
</template>
 
<script>
import C from "./C.vue";
export default {
  name: "B",
  components: {
    C
  },
};
</script>

 

C.vue

<template>
  <div>
  </div>
</template>
 
<script>
export default {
  name: "C"
};
</script>

A与C使用provide / inject方式进行通信

A使用provide

<template>
  <div>
    <B></B>
  </div>
</template>
 
<script>
import B from "./B.vue";
export default {
  name: "A",
  components: {
    B
  },
  provide: {
    name:"leo"
  }
};
</script>

 

C使用inject

<template>
  <div>
    <span>{{name}}</span>
  </div>
</template>
 
<script>
export default {
  name: "C",
  inject: ["name"]
};
</script>

 

此时,C已经拿到A中的对应的name。但是,我们可能希望:当A中的name是本身某个可变化的数据时,如下:

<template>
  <div>
    <B></B>
  </div>
</template>
 
<script>
import B from "./B.vue";
export default {
  name: "A",
  components: {
    B
  },
  provide:{
    name: this.name
  },
  data() {
    return {
      name: "leo"
    }
  },
  methods:{
    changeName() {
      this.name = "lion"
    }
  }
};
</script>

我们希望当name改变时(如触发changeName方法),对应的C中的name也要相应改变,但是使用以上方式时,C中的name并未随着改变,此时需要我们进一步处理,即处理响应性。

 

2、处理响应性

在上面的例子中,如果我们更改了name,这个变化并不会反映在 inject 的 name property 中。这是因为默认情况下,provide/inject 绑定并不是响应式的。在vue3中,我们可以通过传递一个 ref property 或 reactive 对象给 provide 来改变这种行为(下面展开)。在我们的例子(vue2)中,如果我们想对祖先组件中的更改做出响应,我们需要将 provide 传值进行改变。

A使用provide,此时传入的应是一个响应式对象(如以下的obj)

<template>
  <div>
    <B></B>
  </div>
</template>
 
<script>
import B from "./B.vue";
export default {
  name: "A",
  components: {
    B
  },
  provide() {
    return {
      obj:this.obj // 传入一个响应式对象
    }
  },
  data() {
    return {
      obj: {
        name:"leo"
      }
    }
  },
  methods:{
    changeName() {
      this.obj.name = "lion"
    }
  }
};
</script>

 

C使用inject

<template>
  <div>
    <span>{{obj.name}}</span>
  </div>
</template>
 
<script>
export default {
  name: "C",
  inject: ["obj"] // 接收响应式对象
};
</script>

此时A中的name改变,C中的值也会相应跟着变化。
以上为A向C传数据,如果C向A传数据(或者说C需要改变A中的数据),该如何做?
我们这里不让C直接改变A中的数据,而是将A改变数据的方法通过provide传给C,C执行该方法,触发改变A中的数据。

A使用provide传入一个方法

<template>
  <div>
    <span>{{obj.name}}</span>
    <B></B>
  </div>
</template>
 
<script>
import B from "./B.vue";
export default {
  name: "A",
  components: {
    B
  },
  provide() {
    return {
      changeVal: this.changeName // 传入一个方法
    }
  },
  data(){
    return {
      obj: {
        name:"leo"
      }
    }
  },
  methods: {
    changeName(val) { // C中触发该方法执行,此时变成"lion"
      this.obj.name = val
    }
  }
};
</script>

 

C使用inject

<template>
  <div>
    <span @click="changeName">点击改变A组件数据</span>
  </div>
</template>
 
<script>
export default {
  name: "C",
  inject: ["changeVal"], // 接收一个方法
  methods: {
    changeName() {
      this.changeVal("lion") // 执行此方法,改变A中的数据
    }
  }
};
</script>

以上就是在vue2中对provide / inject的基本使用。

 

三、vue3中使用

1、Provide

在 setup() 中使用 provide 时,我们首先从 vue 显式导入 provide 方法。这使我们能够调用 provide 来定义每个 property。
provide 函数允许你通过两个参数定义 property:

  • name (<String> 类型)
  • value

使用A组件,provide 的值可以按如下方式重构:

<template>
  <C />
</template>
 
<script>
import { provide } from 'vue'
import C from './C.vue'
 
export default {
  components: {
    C
  },
  setup() {
    provide('location', 'North Pole')
    provide('geolocation', {
      longitude: 90,
      latitude: 135
    })
  }
}
</script>

 

2、Inject

在 setup() 中使用 inject 时,也需要从 vue 显式导入。导入以后,我们就可以调用它来定义暴露给我们的组件方式。
inject 函数有两个参数:

  • 要 inject 的 property 的 name
  • 默认值 (可选)

使用C组件,可以使用以下代码对其进行重构:

<script>
import { inject } from 'vue'
 
export default {
  setup() {
    const userLocation = inject('location', 'The Universe')
    const userGeolocation = inject('geolocation')
 
    return {
      userLocation,
      userGeolocation
    }
  }
}
</script>

 

3、vue3中处理响应性的方式

为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 或 reactive。

ref 或 reactive的使用

<template>
  <C />
</template>
 
<script>
import { provide, reactive, ref } from 'vue'
import C from './C.vue'
 
export default {
  components: {
    C
  },
  setup() {
    const location = ref('North Pole')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })
 
    provide('location', location)
    provide('geolocation', geolocation)
  }
}
</script>

现在,如果这两个 property 中有任何更改,C组件也将自动更新!

同样的,需要在C中修改它的祖先组件的数据,需像vue2一样在provide传入一个方法

<template>
  <C />
</template>
 
<script>
import { provide, reactive, ref } from 'vue'
import C from './C.vue'
 
export default {
  components: {
    C
  },
  setup() {
    const location = ref('North Pole')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })
 
    const updateLocation = () => {
      location.value = 'South Pole'
    }
 
    provide('location', location)
    provide('geolocation', geolocation)
    provide('updateLocation', updateLocation) // 传入一个方法
  }
}
</script>

 

C中使用inject

<script>
import { inject } from 'vue'
 
export default {
  setup() {
    const userLocation = inject('location', 'The Universe')
    const userGeolocation = inject('geolocation')
    const updateUserLocation = inject('updateLocation')
 
    return {
      userLocation,
      userGeolocation,
      updateUserLocation // 执行该方法,触发祖先组件方法执行,从而改变数据
    }
  }
}
</script>

 

最后,如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly

<template>
  <C />
</template>
 
<script>
import { provide, reactive, readonly, ref } from 'vue'
import C from './C.vue'
 
export default {
  components: {
    C
  },
  setup() {
    const location = ref('North Pole')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })
 
    const updateLocation = () => {
      location.value = 'South Pole'
    }
    // 使用readonly,数据只读
    provide('location', readonly(location))
    provide('geolocation', readonly(geolocation))
    provide('updateLocation', updateLocation)
  }
}
</script>

 

标签:Vue,name,Provide,provide,vue,inject,组件,import,Inject
From: https://www.cnblogs.com/Zzbj/p/17701768.html

相关文章

  • vue3的ref、reactive的使用
    一、介绍ref和reactive是Vue3中用来实现数据响应式的API,一般情况下,ref推荐定义基本数据类型,reactive推荐定义引用数据类型(对象或数组) 二、ref与reactive对比<template><p>{{person.name}}</p><p>{{person.long}}</p><p>{{age}}</p><p>{{info.addr......
  • Vue组件懒加载
    在当今快节奏的数字世界中,网站性能对于吸引用户和取得成功至关重要。然而,对于像首页这样的页面,在不影响功能的前提下优化性能就成了一项挑战。这就是Vue组件懒加载的用武之地。通过将非必要元素的加载推迟到可见时进行,开发人员可以增强用户体验,同时确保登陆页面的快速加载。懒......
  • 从零开始学习Vue3路由,提升你的前端开发技能
    Vue3是当前最流行的前端框架之一,它提供了许多方便的功能和工具,其中路由(Router)就是其中之一。本文将介绍如何在Vue3中使用路由。安装和使用VueRouter首先,我们需要安装VueRouter。在终端中输入以下命令:npminstallvue-router@next--save接下来,我们需要创建一个路由实例。在......
  • vue父组件值更新子组件没更新
    因为父组件和子组件的数据单向绑定关系,子组件中的数据并不是从父组件中获取的而是通过props传递的。因此只更新父组件的数据不会自动更新子组件中的数据。需要在子组件中通过watch监听num的变化,将最新的值传递给变量,从而更新展示。点击清空button会把num重新赋值,自动触发watch监听......
  • Vue3引入滑块验证组件-2分钟搞定
    手把手视频地址:https://www.bilibili.com/video/BV1Nu4y1r7Wr/安装npminstall--savevue3-slide-verify登录页面引入template下<template><divclass="login"> <el-cardclass="cover"v-if="loginUser.data.user"> <slide......
  • 【Vue】定义配置方法&数据代理
    hello,我是小索奇,精心制作的Vue教程持续更新哈,想要学习&巩固&避坑就一起学习叭~Object定义配置方法代码引出数据代理,先上代码,后加解释<!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>回顾Object.defineproperty方法</title></head><body&......
  • Vue-基本语法及事件绑定
    一.基本语法v-bind绑定:双大括号不能在HTMLattributes中使用。想要响应式地绑定一个attribute,应该使用 v-bind 指令代码展示:<divid="app"><spanv-bind:title="message"v-html="tips"></span></div><script>letvue=newVue(......
  • vue样式穿透
    本文转载自https://www.jb51.net/article/253428.htm#_label0,转载仅供学习使用.scoped属性我们在vue组件写样式一般是在<style>标签里面,但是我们在这里的样式默认是全局样式,如果其它组件的class名取重复了则会导致样式污染。所以vue支持在<style>标签添加scoped属性,这样当前组......
  • 15-Vue核心-列表过滤和列表排序
    列表过滤 监视属性,实现列表过滤<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>基本列表</title><!--引入Vue--><scripttype="text/javascript......
  • vuejs+antv-g6绘制图表
    该内容包括antv-g6官网地址、antv-g6的基本使用(包括自定义节点、常用插件(右键菜单等)、基本事件、目前我所遇到的一些需求)。1、antv-g6的官网地址:https://g6.antv.antgroup.com/examples2、安装antv-g6组件npminstall@antv/g6 3、创建antvView.vue文件使用antv/g6......