解读vue3中的$refs、$parent、$root、provide 和 inject

ref和$refs

ref 用于注册元素或子组件的引用。如果用于普通 DOM 元素,引用将是元素本身;如果用于子组件,引用将是子组件的实例

如果使用选项式 API,引用将被注册在组件的 this.$refs 对象里:

<!-- 存储为 this.$refs.p -->
<p ref="p">hello</p>

使用组合式 API,引用将存储在与名字匹配的 ref 里:

<template>
  <p ref="p">hello</p>
</template>
<script setup>
import {
    
     ref } from 'vue'
const p = ref()
</script>

需要注意的是,我们可以在组件内部使用 $refs 来访问子组件的方法和数据。但是在使用 $refs 时需要注意,如果使用不当可能会导致代码出错。另外,如果滥用 $refs,可能会导致代码耦合性增加,不到必要情况下应尽量避免使用。

$parent

$parent 用于访问当前组件的直接父组件实例。在组件中可以通过 $parent 访问到父组件,进而访问其属性或方法。

需要注意的是,在实际开发中,不推荐使用 $parent的方式,因为它破坏了组件的封装性和复用性,使得组件与其父组件紧耦合起来。推荐通过 propsevents 实现组件之间的通信。
一个使用$parent的示例如下:
父组件代码:

<template>
  <div>
    <child-component></child-component>
  </div>
</template>

子组件代码:

<template>
  <div>
    <button @click="$parent.foo()">Click Me</button>
  </div>
</template>

<!-- Vue Instance -->
<script>
  export default {
    
    
    methods: {
    
    
      foo() {
    
    
        console.log("Parent Method Called!");
      }
    }
  }
</script>

在这个示例中,我们定义了一个 ParentComponent 和一个 ChildComponent。在 ParentComponent 的模板中,我们渲染了一个 ChildComponent 的实例。在 ChildComponent 的模板中,我们定义了一个按钮元素,并在点击事件处理函数中通过 $parent 访问了父组件实例中的 foo() 方法。

$root

$root用来访问当前 Vue 应用的根组件。在组件中可以通过 $root访问到根组件实例,进而访问其属性或方法。
其用法和上面的$parent相同,在实际的开发中,也不推荐这种方法,具体的示例代码与上面相似,这里不再赘述

provide 和 inject

provideinject 是 Vue 3 中用于跨层级组件通信的一对API,父组件通过 provide 方法向下传递数据,子组件通过 inject 方法获取数据。

provide()

provide提供一个值,可以被后代组件注入。
provide() 接受两个参数:第一个参数是要注入的 key,可以是一个字符串或者一个 symbol,第二个参数是要注入的值。

在组合式API中示例代码如下:

<script setup>
import {
    
     ref, provide } from 'vue'
import {
    
     fooSymbol } from './injectionSymbols'
// 提供静态值
provide('foo', 'bar')
// 提供响应式的值
const count = ref(0)
provide('count', count)
// 提供时将 Symbol 作为 key
provide(fooSymbol, count)
</script>

在选项式API中示例代码如下:

const s = Symbol()

export default {
    
    
  provide: {
    
    
    foo: 'foo',
    [s]: 'bar'
  }
}

inject()

inject注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。
inject()中的第一个参数是注入的 key。Vue 会遍历父组件链,通过匹配 key 来确定所提供的值。如果父组件链上多个组件对同一个 key 提供了值,那么离得更近的组件将会“覆盖”链上更远的组件所提供的值。如果没有能通过 key 匹配到值,inject() 将返回 undefined,除非提供了一个默认值。

第二个参数是可选的,即在没有匹配到 key 时使用的默认值。它也可以是一个工厂函数,用来返回某些创建起来比较复杂的值。如果默认值本身就是一个函数,那么你必须将 false 作为第三个参数传入,表明这个函数就是默认值,而不是一个工厂函数。

在组合式API中示例代码如下:

<script setup>
import {
    
     inject } from 'vue'
import {
    
     fooSymbol } from './injectionSymbols'
// 注入值的默认方式
const foo = inject('foo')
// 注入响应式的值
const count = inject('count')
// 通过 Symbol 类型的 key 注入
const foo2 = inject(fooSymbol)
// 注入一个值,若为空则使用提供的默认值
const bar = inject('foo', 'default value')
// 注入一个值,若为空则使用提供的工厂函数
const baz = inject('foo', () => new Map())
// 注入时为了表明提供的默认值是个函数,需要传入第三个参数
const fn = inject('function', () => {
    
    }, false)
</script>

在选项式API中示例代码如下:

export default {
    
    
  inject: ['foo'],
  created() {
    
    
    console.log(this.foo)
  }
}

provide 和 inject 通常成对一起使用,使一个祖先组件作为其后代组件的依赖注入方,无论这个组件的层级有多深都可以注入成功,只要他们处于同一条组件链上。通过 provide 方法可以在上层组件中注册数据,并传递给下层子组件;而通过 inject 方法可以在子组件中获取到上层组件中注册的数据,从而实现跨层级的组件通信。

总结

  1. $refs 适用于需要访问子组件或者 DOM 元素的场景。
  2. $parent 适用于父子组件之间进行通信的场景,但是因为会使组件之间的耦合性增加,导致代码的可维护性降低,不到必要情况下应尽量避免使用。
  3. $root 适用于全局状态管理和组件引用的场景。但是因为会使组件之间的耦合性增加,导致代码的可维护性降低,不到必要情况下应尽量避免使用。
  4. provideinject 适用于父子组件之间进行数据传递的场景。

猜你喜欢

转载自blog.csdn.net/w137160164/article/details/131121411