defineExpose() 和 ref 属性
# defineExpose() 和 ref 属性
# 1. defineExpose 函数
defineExpose
是 Vue 3 中的新 API,用于显式暴露子组件的数据或方法给父组件。它通常用于 <script setup>
语法下,让父组件可以访问和调用子组件中的数据和方法。
在 Vue 2 中,父组件可以通过 $refs
获取子组件实例并调用其方法。然而,在 Vue 3 的 <script setup>
语法下,组件实例不再自动暴露给外部。为了解决这个问题,Vue 3 引入了 defineExpose
函数。
通过 defineExpose
函数可以将子组件的方法和数据暴露出去。任何组件在获取了子组件的引用实例后,都可以直接调用子组件暴露出去的方法或访问其数据。
# defineExpose 语法格式
import { ref, defineExpose } from 'vue';
// 定义子组件的数据或方法
let name = ref('张三');
let age = ref(18);
// 使用 defineExpose 函数暴露数据或方法给父组件
defineExpose({
name,
age,
someMethod() {
console.log('子组件的方法');
}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用 defineExpose 示例
子组件通过defineExpose暴露数据
<script lang="ts" setup>
import { ref, defineExpose } from 'vue';
// 定义子组件的数据或方法
let name = ref('张三');
let age = ref(18);
function someMethod() {
console.log('子组件的方法');
}
// 使用 defineExpose 函数暴露数据或方法给父组件
defineExpose({
name,
age,
someMethod
});
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
父组件调用子组件暴露出去的数据
<template>
<Person ref="personRef"/>
<button @click="test">测试</button>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import Person from './components/Person.vue';
// 定义 ref 引用,用于获取子组件实例
let personRef = ref<{ name: string; age: number; someMethod: () => void } | null>(null);
// 方法:测试组件实例
function test() {
if (personRef.value) {
// 访问子组件暴露的数据
console.log(personRef.value.name); // 打印子组件的 name
console.log(personRef.value.age); // 打印子组件的 age
// 调用子组件暴露的方法
personRef.value.someMethod(); // 调用子组件的方法
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
总结
defineExpose
是 Vue 3 中用于显式暴露子组件数据和方法给父组件的 API。- 它解决了
<script setup>
语法下无法自动暴露子组件实例的问题。 - 通过
defineExpose
,父组件可以方便地访问子组件的状态和方法,增强了组件之间的交互性和可维护性。
# 2. 标签的 ref 属性
作用:用于注册模板引用。
- 用在普通
DOM
标签上,获取的是DOM
节点。 - 用在组件标签上,获取的是组件实例对象。
# 用在普通 DOM
标签上
步骤
- 在普通
DOM
标签上添加ref
属性并指定引用名。 - 在
<script>
中通过ref
函数创建对应引用,并初始化为null
。 - 通过引用的
value
属性访问DOM
节点。
<template>
<div class="person">
<h1 ref="title1">尚硅谷</h1>
<h2 ref="title2">前端</h2>
<h3 ref="title3">Vue</h3>
<input type="text" ref="input"> <br><br>
<button @click="showLog">点我打印内容</button>
</div>
</template>
<script lang="ts" setup name="Person">
import { ref } from 'vue';
// 定义 ref 引用
let title1 = ref<HTMLElement | null>(null);
let title2 = ref<HTMLElement | null>(null);
let title3 = ref<HTMLElement | null>(null);
let input = ref<HTMLInputElement | null>(null);
function showLog() {
// 通过 id 获取元素
const t1 = document.getElementById('title1');
// 打印内容,通过 id 获取的元素
console.log((t1 as HTMLElement).innerText); // 使用 as 进行类型断言
console.log((<HTMLElement>t1).innerText); // 使用 <类型> 进行类型断言
console.log(t1?.innerText); // 使用可选链操作符
/************************************/
// 打印内容,通过 ref 获取的元素
console.log(title1.value?.innerText); // 打印 title1 内容
console.log(title2.value?.innerText); // 打印 title2 内容
console.log(title3.value?.innerText); // 打印 title3 内容
console.log(input.value); // 打印 input 节点
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 用在组件标签上
步骤
- 在组件标签上添加
ref
属性并指定引用名。 - 在
<script>
中通过ref
函数创建对应引用,并初始化为null
。 - 在子组件中使用
defineExpose
函数暴露需要给父组件访问的数据或方法。 - 通过引用的
value
属性访问组件实例对象。
<!-- 父组件App.vue -->
<template>
<Person ref="ren"/>
<button @click="test">测试</button>
</template>
<script lang="ts" setup name="App">
import { ref } from 'vue';
import Person from './components/Person.vue';
// 定义 ref 引用
let ren = ref<{ name: string; age: number } | null>(null);
function test() {
if (ren.value) {
console.log(ren.value.name); // 打印子组件的 name
console.log(ren.value.age); // 打印子组件的 age
}
}
</script>
<!-- 子组件Person.vue -->
<script lang="ts" setup name="Person">
import { ref, defineExpose } from 'vue';
// 定义子组件的数据
let name = ref('张三');
let age = ref(18);
// 使用 defineExpose 将组件中的数据暴露给外部
defineExpose({ name, age });
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08