# Vue3教程 - 15 ref与$parent

如果想获取元素和组件的 DOM,可以使用标签的 ref 来实现。

ref 可以添加在普通的 HTML 标签上,也可以添加在组件标签上:

  • 添加在普通的HTML标签上,获取的是 DOM 节点;
  • 添加在 Vue 组件标签上,获取的是组件实例。

如果在以前,我们会使用 document.getElementById() 的方式来获取到 DOM 元素:

<template>
  <div>www.doubibiji.com</div>
  <div id="title-div">逗比笔记</div>

  <button @click="getDom">获取DOM</button>
</template>

<!-- setup -->
<script lang="ts" setup>

// 获取Dom
function getDom() {
  let titleDiv = document.getElementById('title-div')
  console.log(titleDiv)
}

</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

但是在 Vue 中不推荐使用这种方式,在 Vue 中,我们会定义很多的组件,一个页面是可能是由不同的人开发的不同的组件,组件的ID 很可能会存在重复的情况,所以使用这种方式,会导致冲突。


# 15.1 普通元素添加ref属性

下面就来介绍使用 ref 属性来获取 DOM。

  1. 给标签添加一个 ref 属性;
  2. 使用 ref 定义一个变量,这个变量的名称需要和标签中的 ref 的属性值相同。
<template>
  <div>www.doubibiji.com</div>
  <div ref="title">逗比笔记</div>

  <button @click="getDom">获取DOM</button>
</template>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue';

// 创建一个title变量,用于存储元素的内容
// 这里的名称需要和标签的ref的名称对应
let title = ref()

// 获取Dom
function getDom() {
  // 直接输出title.value
  console.log(title.value)   // <div>逗比笔记</div>
}

</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

通过 let title = ref() 就可以获取到 ref="title" 的元素。


# 15.2 组件上添加ref属性

同样,ref 属性还可以添加到组件上,可以通过ref 属性获取到组件实例。

定义一个 Person 组件:

<template>
    <div>{{ name }}</div>
    <div>{{ age }}</div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue';

let name = ref('Doubi')
let age = ref(13)

// 导出变量
defineExpose({ name, age })
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

这里要解释一下,这里使用了 defineExpose 函数,这个函数的参数是一个对象,作用是导出组件中的数据。

在这里通过 defineExpose 导出的数据,待会在父组件中使用 Person 组件并通过 ref 属性获取 Person 组件实例的时候,可以获取到这些导出的数据。


在父组件中使用 Person 组件并添加 ref 属性:

<template>
  <Person ref="person" />

  <button @click="changePerson">修改Person</button>
</template>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue';
// 引入person组件
import Person from '@/components/Person.vue';

// 获取到Person组件实例
let person = ref()

function changePerson() {
  // 获取组件中的使用defineExpose导出的变量
  console.log(person.value.name)

  // 修改子组件的值
  person.value.name = 'Niubi';
  person.value.age = 14;
}

</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

在上面的代码中,引入并使用了 Person 组件,在使用的时候,添加了 ref 属性。在脚本中通过 let person = ref() 获取到的就是组件的实例了。

此时通过 person.value.domain 就可以获取到组件中通过 defineExpose() 函数导出的数据,否则是获取不到的。

这样通过 ref 就实现了在父组件中修改子组件中的数据。


其实在父组件中还可以通过一个 $refs 获取所有带 ref 属性的子元素。

举个栗子:

<template>
  <Person ref="p1" />
  <Person ref="p2" />

  <button @click="getAllChild($refs)">获取所有子组件实例</button>
</template>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue';
// 引入person组件
import Person from '@/components/Person.vue';

function getAllChild(refs: any) {
  // refs 是所有子组件列表
  for (let key in refs) {
    // 获取子组件的属性
    console.log('name:', refs[key].name);
  }
}

</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

了解一下。

# 15.3 $parent

上面通过 ref 实现在父组件中修改子组件中的数据,还可以在子组件中,通过 $parent 修改父组件中的数据。

首先在父组件中定义数据:

HomePage.vue

<template>
  <div>{{ domain }}</div>
  <div>{{ title }}</div>

  <Person />
</template>

<!-- setup -->
<script lang="ts" setup>
import { ref } from 'vue';
import Person from '@/components/Person.vue';

let domain = ref('www.doubibiji.com');
let title = ref('逗比笔记');

// 导出数据
defineExpose({ domain, title })

</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在父组件中使用 defineExpose() 导出数据,这样在子组件中才能获取父组件的数据。


在子组件通过 $parent 来获取父组件,然后获取父组件的数据。

Person.vue 子组件:

<template>
    <button @click="changeParentData($parent)">修改父组件数据</button>
</template>

<!-- setup -->
<script lang="ts" setup>

function changeParentData(parent: any) {
    console.log('domain:', parent.domain);
    parent.domain = 'doubibiji.com';
    parent.title = '我的笔记';
}

</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

在子组件中,通过 $parent 获取到父组件,然后传递给函数,在函数中通过父组件修改父组件的数据。

这样通过 $parent 就实现了在子组件中修改父组件中的数据。