Vue3 零基础每日笔记(005):ref 响应式基础——为什么 script 里要 .value

一、前言

前几篇代码里一直在写 ref,今天终于把它讲透。这是 Vue3 响应式的第一块基石:什么是响应式?为什么 script 里要 .value,模板里又不用?为什么普通变量页面不更新?一篇全部搞懂。

二、先理解:什么是响应式

写个反例感受一下,用普通变量渲染页面:

vue 复制代码
<template>
  <p>{{ msg }}</p>
  <button @click="msg = '我变了'">改数据</button>
</template>

<script setup>
// 普通变量,没有包 ref
let msg = '我一开始的样子'
</script>

点击按钮,页面纹丝不动。因为 Vue 根本不知道 msg 变了------它不是响应式数据。

换成 ref 包一层:

vue 复制代码
<template>
  <p>{{ msg }}</p>
  <button @click="msg = '我变了'">改数据</button>
</template>

<script setup>
import { ref } from 'vue'

// ref 包一层,变成响应式数据
const msg = ref('我一开始的样子')
</script>

再点,页面立刻更新 。这就是响应式:数据变化时,用到它的页面部分自动更新

三、ref 的本质:给数据套一层"监控壳"

通俗理解:ref(初始值) 会把你的数据装进一个带监控的盒子,Vue 盯着这个盒子,数据一有风吹草动,立刻通知页面更新。

在 script 里打印看看 ref 到底长什么样:

js 复制代码
const count = ref(0)
console.log(count)
// 输出:RefImpl { _value: 0, ... }

它是个对象,真正的值藏在 .value 属性里。所以------

script 里操作数据,必须通过 .value

js 复制代码
const count = ref(0)

count.value        // 读:拿到 0
count.value = 10   // 写:改成 10,页面自动更新
count.value += 5   // 自增:变成 15

console.log(count)      // ❌ 打印的是盒子对象,不是 0
console.log(count.value) // ✅ 打印 0

模板里不用 .value,直接写名字:

vue 复制代码
<template>
  <!-- ✅ 直接写 count,不用 count.value -->
  <p>{{ count }}</p>
</template>

为什么模板里不用?因为 Vue 编译模板时会自动帮你解包 (自动加 .value)。这不是语法不一致,是 Vue 设计好的------模板里写 .value 反而多余。

一句话记住:script 里要 .value,模板里不用

四、ref 包对象:深层响应式

ref 不只能包数字字符串,包对象、数组也完全没问题,而且是深层响应式------嵌套多深的属性改了都会更新:

vue 复制代码
<template>
  <p>姓名:{{ user.name }}</p>
  <p>城市:{{ user.address.city }}</p>
  <button @click="user.address.city = '上海'">搬家</button>
</template>

<script setup>
import { ref } from 'vue'

const user = ref({
  name: '小明',
  address: {
    city: '北京'  // 深层嵌套,依然响应式
  }
})
</script>

点按钮,"城市:上海"立刻更新。深层属性通过 .value 一路点下去访问,模板里 Vue 自动解包,直接 user.address.city 就行。

五、三个高频新手坑(重点看)

坑 1:忘了 .value,页面不更新

js 复制代码
const count = ref(0)

function add() {
  count++           // ❌ 改的是盒子上的临时值,页面不动
  count.value++     // ✅ 正确
}

现象:代码不报错(或报 NaN),但页面死活不更新。90% 是忘写 .value

坑 2:解构后丢失响应式

js 复制代码
const count = ref(0)

// ❌ 解构的一瞬间,就把"当时的值 0"复制出来了
// 之后 count.value 再怎么变,num 都是死的 0
let num = count.value

// ✅ 要用就用 count.value,别提前解构

(解构对象的场景要用 toRefs,那是 012 篇的主角,这里先埋个伏笔。)

坑 3:异步/延时后页面不更新?不存在的

js 复制代码
const msg = ref('加载中')

// 定时器里改 ref,页面照样更新,放心用
setTimeout(() => {
  msg.value = '加载完成'
}, 1000)

有些框架的数据脱离响应式要在特定时机刷新,Vue3 的 ref 在任何地方改都触发更新------这正是它的强大之处。

六、综合实战:点赞 + 自动切换文案

用 ref 写个完整交互小案例,把本篇知识点全用上:

vue 复制代码
<template>
  <h3>{{ article.title }}</h3>
  <p>{{ liked ? '❤️ 已点赞' : '🤍 点个赞吧' }}</p>
  <p>点赞数:{{ count }}</p>
  <button @click="toggle">{{ liked ? '取消赞' : '点赞' }}</button>
</template>

<script setup>
import { ref } from 'vue'

const article = ref({ title: 'Vue3 ref 一篇讲透' })
const count = ref(66)
const liked = ref(false)

function toggle() {
  if (liked.value) {
    liked.value = false
    count.value--        // 取消赞,数量减 1
  } else {
    liked.value = true
    count.value++        // 点赞,数量加 1
  }
}
</script>

运行后:点赞按钮在两种文案间切换,数字实时增减,emoji 同步变化------三个 ref 数据联动,页面全自动更新。

【截图位置:点赞前(灰心+66)与点赞后(红心+67)的对比效果】

七、今日小结

  • 响应式 = 数据变,视图自动变
  • ref(初始值) 创建响应式数据,真值存在 .value
  • script 里 .value,模板里不用
  • ref 包对象是深层响应式
  • 三大坑:忘 .value、提前解构、(误以为)异步不更新

作者:陈志宝

下篇预告

ref 什么都能包,但每次都 .value 有点烦?下一篇讲它的好兄弟 reactive:专门包对象、不用 .value,以及两者到底该选谁。

相关推荐
海鸥两三1 小时前
Mac电脑使用 Tabby 部署前端项目到阿里云服务器完整教程
前端·macos·阿里云
console.log('npc')1 小时前
2026 实测:Grok 4.5 与 Grok 4.6 怎么选?前端开发、教程写作、Figma 还原选型指南
前端·大模型·ai编程·figma·grok
yyt3630458411 小时前
一次鼠标交互触发两次 Vue flushJobs:把高频交互从 VDOM 里拆出来
前端·vue.js·计算机外设
YUJIANYUE2 小时前
查立得万用查分安卓版(web环境+查询系统免安装单文件一键运行包)
android·前端
知兀2 小时前
框架脚手架搭建,推送github一键使用
javascript·vue.js·ecmascript
慧都小项2 小时前
从 Figma 到 Qt:Qtitan 能减少哪些界面还原工作?
前端·qt·嵌入式·figma·图形界面·工业界面·qtitan
YWL2 小时前
OpenLayers导出功能:地图截图+GeoJSON导出完整方案,从Canvas合并到PDF生成
前端·vue·openlayers
点心的游戏开发世界2 小时前
GDScript 入门笔记(十六):文件读写与数据持久化
开发语言·笔记·游戏引擎·godot
苦瓜小生2 小时前
【前端】【力扣与手撕】十天带你刷完前端算法与手撕,全是最简单好记的最优解法!day4
前端·数据结构·算法·leetcode·面试