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
provide
和 inject
是 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
方法可以在子组件中获取到上层组件中注册的数据,从而实现跨层级的组件通信。
总结:
$refs
适用于需要访问子组件或者 DOM 元素的场景。$parent
适用于父子组件之间进行通信的场景,但是因为会使组件之间的耦合性增加,导致代码的可维护性降低,不到必要情况下应尽量避免使用。$root
适用于全局状态管理和组件引用的场景。但是因为会使组件之间的耦合性增加,导致代码的可维护性降低,不到必要情况下应尽量避免使用。provide
和inject
适用于父子组件之间进行数据传递的场景。