朋友们,不知道你们写代码时有没有经历过这种绝望:明明数据已经更新了,页面上却像什么都没发生一样稳如泰山?别不好意思,我懂!这种时候简直想砸键盘有没有?
但别急,Vue3 带来了一个超级救星——ref() 方法。今天咱们就一起扒扒它的底裤,看看这个看似简单的小函数,到底有多大能耐!
一、先唠唠:为啥我们需要 ref()?
想象一下这个场景:你有个变量 count,想做个简单的计数器。在普通 JavaScript 里,你写个 count++ 就完事了。但在 Vue 里,如果直接这么干,页面根本不会更新!
为什么?因为 Vue 的响应式系统需要追踪数据的变化。普通的变量就像个“独行侠”,变了就变了,谁也不通知。而 ref() 就像给变量配了个“贴身秘书”,变量一变,秘书立刻大喊:“老板变了!快更新页面!”
底层原理小贴士:ref() 背后其实是 Vue 的依赖追踪系统。当你通过 .value 访问时,Vue 会自动收集这个依赖;当 .value 改变时,所有依赖这个值的地方都会自动更新。是不是很像微信朋友圈?你一发状态,所有好友都能看到更新!
二、基础用法:让数字“活”起来
废话不多说,直接上代码!让我们用 ref() 实现那个经典的计数器:
<template>
<div>
<p>你点了 {{ count }} 次,真是够执着的!</p>
<button @click="handleClick">点我试试?</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 关键在这!把普通的数字变成响应式的
const count = ref(0)
const handleClick = () => {
count.value++ // 注意这里要操作 .value
console.log(`当前计数:${count.value}`)
}
</script>
看到没有?就靠 ref(0) 这么个小操作,count 就从普通数字升级成了“响应式大佬”。每次点击按钮,页面上的数字都会乖乖更新。
新手必坑点:刚开始用 ref() 时,十个人有九个会忘记写 .value!记住,在 <script setup> 里操作 ref 变量时,必须通过 .value;但在 <template> 里不用,Vue 会自动帮你解开。
三、进阶玩法:ref() 能包装哪些类型?
你以为 ref() 只能包装数字?太小看它了!这货是个“万能包装机”,什么类型都能处理:
// 各种数据类型一网打尽
const num = ref(0) // 数字
const str = ref('Hello') // 字符串
const bool = ref(true) // 布尔值
const obj = ref({ name: '小明', age: 18 }) // 对象
const arr = ref([1, 2, 3]) // 数组
const nullVal = ref(null) // 甚至 null 和 undefined
特别提醒:包装对象时,其实用 reactive() 更合适,但 ref() 也能胜任。这就好比能用菜刀切西瓜,但用西瓜刀更专业!
四、实战演示:做一个“个人信息卡”
光说不练假把式,来做个实际点的例子——一个可以编辑的个人信息卡片:
<template>
<div class="profile-card">
<h2>你的个人信息</h2>
<div class="field">
<label>姓名:</label>
<input v-model="name" placeholder="输入你的大名">
</div>
<div class="field">
<label>年龄:</label>
<input type="number" v-model="age" placeholder="输入年龄">
</div>
<div class="field">
<label>简介:</label>
<textarea v-model="bio" placeholder="介绍一下自己吧~"></textarea>
</div>
<div class="preview">
<h3>实时预览:</h3>
<p><strong>姓名:</strong>{{ name || '未知' }}</p>
<p><strong>年龄:</strong>{{ age || '未知' }}</p>
<p><strong>简介:</strong>{{ bio || '这个家伙很懒,什么都没写' }}</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 定义响应式数据
const name = ref('')
const age = ref('')
const bio = ref('')
</script>
<style scoped>
.profile-card {
max-width: 500px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.field {
margin-bottom: 15px;
}
.field label {
display: inline-block;
width: 60px;
font-weight: bold;
}
.field input, .field textarea {
width: 200px;
padding: 5px;
border: 1px solid #ccc;
border-radius: 4px;
}
.preview {
margin-top: 20px;
padding: 15px;
background: #f5f5f5;
border-radius: 4px;
}
</style>
这个例子展示了多个 ref() 的协同工作。每个输入框都绑定一个 ref,数据一变,预览区域实时更新。这就是响应式的魅力——数据驱动视图,不用你手动操作 DOM!
五、ref() 在组合式函数中的妙用
Vue3 的组合式 API 允许我们提取可复用的逻辑。ref() 在这里面扮演了关键角色:
// useCounter.js - 一个可复用的计数器逻辑
import { ref } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
const reset = () => {
count.value = initialValue
}
// 返回所有需要暴露的内容
return {
count,
increment,
decrement,
reset
}
}
然后在组件中使用:
<template>
<div>
<p>计数:{{ count }}</p>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
<button @click="reset">重置</button>
</div>
</template>
<script setup>
import { useCounter } from './useCounter'
const { count, increment, decrement, reset } = useCounter(10) // 从10开始计数
</script>
这种逻辑复用的方式,让代码组织变得更加灵活和清晰!
六、模板引用:用 ref 直接操作 DOM
ref() 还有个超能力——直接获取 DOM 元素的引用:
<template>
<div>
<input ref="inputRef" type="text" placeholder="我会自动获得焦点">
<button @click="focusInput">点我让输入框聚焦</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 创建一个 ref 来存储 DOM 元素
const inputRef = ref(null)
const focusInput = () => {
// 直接操作 DOM!
inputRef.value?.focus()
}
// 组件挂载后自动聚焦
onMounted(() => {
inputRef.value?.focus()
})
</script>
这种方式比用 document.querySelector 优雅多了,而且完全符合 Vue 的设计理念。
七、ref() 与 reactive() 的 PK
经常有人问:ref() 和 reactive() 到底用哪个?
简单来说:
- ref():适合基本类型(number, string, boolean),也可以用对象/数组
- reactive():专门为对象类型设计
// 用 ref 包装对象
const userRef = ref({ name: '小红', age: 20 })
// 用 reactive 包装对象
const userReactive = reactive({ name: '小红', age: 20 })
// 使用时的区别
console.log(userRef.value.name) // 需要 .value
console.log(userReactive.name) // 直接访问
个人建议:单一的基本类型值用 ref(),复杂的对象结构用 reactive(),这样代码更清晰。
八、避坑指南与最佳实践
- 别忘了 .value:在 script 里操作 ref 时,
.value是你的好朋友 - 避免过度使用:不是所有数据都需要响应式,静态数据就用普通变量
- 组合式函数返回 ref:这样在使用时可以直接解构而失去响应性
- 模板 ref 的生命周期:模板 ref 在组件挂载后才能访问,记得在 onMounted 里使用
// 不好的做法 - 在 setup 中立即访问模板 ref
const inputRef = ref(null)
console.log(inputRef.value) // null,因为组件还没挂载
// 好的做法 - 在 onMounted 中访问
onMounted(() => {
console.log(inputRef.value) // 正确的 DOM 元素
})
九、总结
ref() 虽然看起来简单,但却是 Vue3 响应式系统的基石。它让我们的数据变得“有知觉”,能够自动驱动视图更新。从基本类型到 DOM 操作,从组件逻辑到组合式函数,ref() 无处不在。
记住,用好 ref() 的关键就是理解它的 .value 访问方式和响应式原理。一旦掌握了这些,你就能写出更加简洁、高效的 Vue 代码!
怎么样,现在是不是觉得 ref() 这个“小不点”其实蕴含着“大能量”?赶紧去你的项目中试试吧,保证让你的开发体验爽到飞起!
看完要点赞,代码无bug! 🚀
908

被折叠的 条评论
为什么被折叠?



