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

2023-10-14 09:03:07 浏览数 (2)

ref和$refs

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

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

代码语言:javascript复制
<!-- 存储为 this.$refs.p -->
<p ref="p">hello</p>

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

代码语言:javascript复制
<template>
  <p ref="p">hello</p>
</template>
<script setup>
import { ref } from 'vue'
const p = ref()
</script>

需要注意的是,我们可以在组件内部使用 refs 来访问子组件的方法和数据。但是在使用 refs 时需要注意,如果使用不当可能会导致代码出错。另外,如果滥用

$parent

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

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

代码语言:javascript复制
<template>
  <div>
    <child-component></child-component>
  </div>
</template>

子组件代码:

代码语言:javascript复制
<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访问到根组件实例,进而访问其属性或方法。 其用法和上面的

provide 和 inject

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

provide()

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

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

代码语言:javascript复制
<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中示例代码如下:

代码语言:javascript复制
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中示例代码如下:

代码语言:javascript复制
<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中示例代码如下:

代码语言:javascript复制
export default {
  inject: ['foo'],
  created() {
    console.log(this.foo)
  }
}

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

总结

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

0 人点赞