ref
1. 先搞懂一个核心问题:Vue 怎么知道你改了数据,然后刷新页面?
Vue 需要盯着你的变量,一变就自动更新网页上显示的内容。
普通变量 Vue 盯不住:
ts
let num = 1
num = 2
Vue:完全没感知,页面数字不会变。
2. ref 干的唯一一件事:给变量套一层「监控外壳」
ref(里面的值) 会生成一个外壳对象,Vue 专门盯着这个外壳。
ts
import { ref } from 'vue'
const num = ref(1)
底层真实结构可以理解成这样:
js
num = {
// 真正存数字的地方
value: 1,
// Vue偷偷藏了监听代码
}
- 外壳
numVue能看见、能监控; - 真正的数据藏在
.value里面。
改数据的时候,必须改 .value
ts
num.value = 2
Vue 检测到你修改了外壳里的 value,立刻刷新页面。
如果你写成 num = 2,直接把整个监控外壳扔掉了,Vue 失去监控,页面不动。
3. 模板里为什么不用 .value?
模板是 Vue 单独处理的语法,它会自动帮你读取 .value。
vue
<!-- 不用写 num.value -->
<div>{{ num }}</div>
4. 最简可运行对比,一眼看出差别
例子1:不用 ref(页面不更新)
js
<script setup>
let count = 0
function add() {
count++
console.log(count) // 控制台数字变了,页面不动
}
</script>
<template>
<p>数字:{{ count }}</p>
<button @click="add">点我+1</button>
</template>
例子2:用 ref(页面同步更新)
js
<script setup>
import { ref } from 'vue'
// 套监控外壳
const count = ref(0)
function add() {
// 修改外壳内部的值
count.value++
}
</script>
<template>
<p>数字:{{ count }}</p>
<button @click="add">点我+1</button>
</template>
5. ref 第二个用途:获取页面DOM标签
你想操作页面上的输入框、按钮,JS原生拿DOM很麻烦,用ref绑定:
js
<script setup>
import { ref, onMounted } from 'vue'
// 空的监控外壳,专门存input元素
const inputDom = ref(null)
// 页面渲染完后
onMounted(() => {
// inputDom.value 就是页面里的input标签
inputDom.value.focus() // 自动光标聚焦输入框
})
</script>
<template>
<!-- ref名字和变量对应 -->
<input ref="inputDom" placeholder="搜索" />
</template>
Vue 把 ref 做成了模板特殊指令,自动帮你完成「查找 DOM、存入变量」这一步,不用手写 querySelector,这是框架封装出来的语法。
补充对比:
js
<input id="searchInput" placeholder="搜索">
<script>
// 原生必须手动根据id获取DOM
const input = document.getElementById('searchInput')
// 页面加载完才能操作
window.onload = function() {
input.focus()
}
</script>
Vue 简化后,不用写选择器,靠同名 ref 自动绑定,是框架提供的便利语法。
6. 一句话终极总结
ref = 给数字/字符串/布尔/DOM标签包一层 Vue 能监控的外壳;
代码里改值要 .value,模板里直接写变量名。
reactive
1. reactive 和 ref 是亲兄弟,作用一样:让数据变响应式,改了页面自动更新
区别只在于装的数据类型不一样:
ref:装单个简单值(数字、字符串、布尔、DOM),要用.valuereactive:专门装 对象、数组 ,不用写.value
2. 先看对比,一眼看懂
场景1:表单对象,用 reactive
ts
import { reactive } from 'vue'
// 把整个表单变成响应式
const form = reactive({
filename: '',
status: '',
id: 0
})
// 直接点属性修改,不用 .value
form.filename = '测试文档.pdf'
form.status = 'success'
场景2:如果硬用 ref 写对象(麻烦)
ts
const form = ref({
filename: ''
})
// 修改必须两层 .value,很啰嗦
form.value.filename = 'xxx'
3. reactive 底层原理
ref 是套一层 { value: xxx }
reactive 直接把整个对象本身变成可监听代理 ,不用包一层盒子,所以不用 .value。
4. 数组也用 reactive
ts
const docList = reactive<DocumentRead[]>([])
// 直接push、修改数组,页面自动刷新
docList.push({ id: 1, filename: 'a.pdf', status: '' })
5. 核心优缺点
优点
修改属性简洁,不用每次打 .value,表单、列表首选。
大坑(重点)
不能直接替换整个对象!会丢失响应式
ts
const form = reactive({ name: '' })
// ❌ 错误,直接覆盖整个对象,Vue 失去监听
form = { name: '新名字' }
// ✅ 正确,只改里面属性
form.name = '新名字'
ref 就没这个问题:
ts
const form = ref({ name: '' })
// 可以直接替换 .value
form.value = { name: '新名字' }
6. ref 和 reactive 选择口诀
- 单个数字/字符串/布尔 / DOM引用 → ref
- 表单、JSON对象、列表数组 → reactive
7. 配套工具 toRefs(高频搭配 reactive)
如果你想把 reactive 对象拆分成单独变量,不丢失响应式:
ts
import { reactive, toRefs } from 'vue'
const form = reactive({ name: '', id: 1 })
// 解构出独立ref变量
const { name, id } = toRefs(form)
// 此时 name、id 是 ref,修改需要 .value
name.value = '张三'
一句话总结
reactive 是 Vue 提供的API,专门把对象、数组转为响应式,直接 .属性 修改,不用写 .value;适合表单、列表这种复杂结构数据。