http://www.manongjc.com/detail/26-krnsyulausdxmlq.html
接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的 property`.value`。
一般用来定义一个基本类型的响应式数据Undefined、Null、Boolean、Number和String,除此之外也可以用来定义简单的`Object`响应式数据,当然一般深层的`Object`等复杂数据均是使用`reactive`定义。
**注意**:在`ts`或者`js`中操作数据需要使用`xxx.value`的形式,而模板中不需要添加`.value`
```ts
import { ref } from 'vue'
const count = ref(0)
const str = ref('hello')
const bool = ref(true)
```
#### 为`ref()`标注类型
`ref`会根据初始化时的值推导其类型:
```ts
import { ref } from 'vue'
// 推导出的类型:Ref<number>
const year = ref(2020)
// => TS Error: Type 'string' is not assignable to type 'number'.
year.value = '2020'
```
有时我们可能想为`ref`内的值指定一个更复杂的类型,可以通过使用`Ref`这个类型:
```ts
import { ref } from 'vue'
import type { Ref } from 'vue'
const year: Ref<string | number> = ref('2020')
year.value = 2020 // 成功!
```
或者,在调用`ref()`时传入一个泛型参数,来覆盖默认的推导行为:
```ts
// 得到的类型:Ref<string | number>
const year = ref<string | number>('2020')
year.value = 2020 // 成功!
```
如果你指定了一个泛型参数但没有给出初始值,那么最后得到的就将是一个包含`undefined`的联合类型:
```ts
// 推导得到的类型:Ref<number | undefined>
const n = ref<number>()
```
#### 访问模板 ref
为了通过组合式 API 获得该模板`ref`,我们需要声明一个同名的`ref`:
```html
<template>
<input ref="input" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 声明一个 ref 来存放该元素的引用
// 必须和模板 ref 同名
const input = ref(null) // 或者标注类型: ref<HTMLInputElement | null>(null)
onMounted(() => {
input.value.focus() // 标注类型后用法:input.value?.focus()
})
</script>
```
**注意**: 只可以在组件挂载后才能访问`ref`。如果你想在模板中的表达式上访问`input`,在初次渲染时会是`null`。这是因为在初次渲染前这个元素还压根不存在呢!
如果你正试图观察一个模板`ref`的变化,确保考虑到`ref`的值为`null`的情况:
```ts
watchEffect(() => {
if (input.value) {
input.value.focus()
} else {
// 此时还未挂载,或此元素已经被卸载(例如通过 v-if 控制)
}
})
```