vue3模板中ref的实现原理

总的来说:
ref 通过对象包装 ({ value })和 getter/setter 拦截 ,在模板编译阶段自动解包 .value,并利用响应式系统(track/trigger)实现依赖收集和更新触发,从而让基本类型和对象都能响应式变化。
精简版:

👉 ref 用对象存值,.value 触发响应式,模板自动解包。


Vue 3 模板中 ref 的实现原理详解

在 Vue 3 中,ref 是一个非常重要的响应式 API,用于创建可变的响应式数据 。它在模板 和组合式 API(Composition API) 中广泛使用。

本文将深入探讨:

  1. ref 的基本用法
  2. ref 在模板中的工作原理
  3. ref 的底层实现机制
  4. 与 reactive 的区别
  5. 示例代码演示

📌 1. ref 的基本用法

ref 用于创建一个响应式引用 ,可以包装基本类型(如 number、string)或对象:

javascript 复制代码
import { ref } from 'vue';

const count = ref(0); // 创建一个响应式 ref,初始值为 0

console.log(count.value); // 访问值需要使用 .value
count.value++; // 修改值

在 模板 中,Vue 会自动解包 .value,所以可以直接使用:

vue 复制代码
<template>
  <button @click="count++">{{ count }}</button>
</template>

📌 注意:

  • 在 JS 中 访问 ref 必须用 .value。
  • 在 模板 中 无需 .value(Vue 自动解包)。

📌 2. ref 在模板中的工作原理

(1)为什么模板里不用 .value?

Vue 的模板编译器 在编译阶段会对 ref 进行特殊处理:

js 复制代码
<template>
  <div>{{ count }}</div>
</template>

会被编译成:

javascript 复制代码
import { ref } from 'vue';

setup() {
  const count = ref(0);
  return { count }; // 返回 ref 对象
}

Vue 在渲染时 自动调用 .value:

javascript 复制代码
// 伪代码:Vue 内部处理
render() {
  return h('div', count.value); // 自动解包
}

(2)ref 在模板中的响应式更新

当 ref.value 变化时,Vue 的响应式系统会触发组件更新:

javascript 复制代码
count.value = 10; // 修改 ref,触发重新渲染

底层机制:

  1. ref 内部使用 ReactiveEffect 进行依赖收集。
  2. 模板中使用 ref 时,Vue 会自动追踪依赖。
  3. 当 ref.value 变化时,触发 组件的重新渲染。

📌 3. ref 的底层实现原理

(1)ref 的核心实现

ref 的源码(简化版):

javascript 复制代码
function ref(value) {
  return {
    _isRef: true, // 标识是 ref 对象
    _value: value, // 存储值
    get value() {
      track(this, 'value'); // 依赖收集
      return this._value;
    },
    set value(newVal) {
      if (newVal !== this._value) {
        this._value = newVal;
        trigger(this, 'value'); // 触发更新
      }
    }
  };
}

📌 关键点:

  • ref 返回一个对象 ,包含 value 的 getter/setter。
  • track() :在 get 时收集依赖(模板、计算属性等)。
  • trigger() :在 set 时触发更新。

(2)ref vs reactive

特性 ref reactive
适用类型 基本类型 + 对象 仅对象/数组
访问方式 .value(JS 中) 直接访问属性
模板解包 自动解包(无需 .value) 无需解包
实现方式 基于 getter/setter 基于 Proxy

为什么 ref 需要 .value?

因为 ref 可以包装基本类型(如 number),而 JavaScript 的 Proxy 无法代理基本类型,所以必须用对象包装。


📌 4. 示例:ref 在模板中的使用

示例 1:计数器

js 复制代码
<template>
  <button @click="increment">{{ count }}</button>
</template>

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

const count = ref(0);

function increment() {
  count.value++; // 修改 ref
}
</script>

✅ 运行效果:

  • 点击按钮,count 自动更新并重新渲染。

示例 2:DOM 引用

js 复制代码
<template>
  <input ref="inputRef" />
  <button @click="focusInput">Focus Input</button>
</template>

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

const inputRef = ref(null); // 存储 DOM 引用

function focusInput() {
  inputRef.value.focus(); // 访问 DOM 元素
}
</script>

✅ 运行效果:

  • 点击按钮,input 自动聚焦。

📌 5. 总结

  1. ref 的作用:创建响应式数据(基本类型 + 对象)。
  2. 模板中的 ref :
    • 自动解包 .value(无需手动写)。
    • 修改 ref.value 触发重新渲染。
  3. 底层原理 :
    • 基于 getter/setter + 依赖收集(track/trigger)。
    • 比 reactive 更灵活(支持基本类型)。
  4. 适用场景 :
    • 基本类型的响应式数据(如 number、string)。
    • 存储 DOM 引用(<div ref="el">)。
    • 需要明确 .value 访问的情况(更可控)。

🚀 进阶建议:

  • 如果想深入 Vue 响应式系统,可以研究 effect、track、trigger 的源码。
  • 在组合式 API 中,ref 和 reactive 可以结合使用。

希望这篇解析能帮助你彻底理解 ref 的工作原理!🎯

相关推荐
雪芽蓝域zzs27 分钟前
第 2 节:基础扩展 - 下拉弹窗常用原生属性
vue.js·elementui
扶风ff1 小时前
新品知识更新太快?用练题簿在线刷题,安排企业培训的小测与复盘
前端·学习·小程序
对空六课1 小时前
支持注意力分析的热力图工具有哪些?
前端·数据库·数据分析
Csvn3 小时前
Vue3 响应式与编译:依赖收集如何升级为节点级靶向更新
前端
星栈4 小时前
pnpm 12 升级实测
前端·javascript
Sirens.4 小时前
Java并发锁详解:六类锁策略与 synchronized 底层原理
java·前端·算法
特创数字科技5 小时前
一个纯本地运行的图片处理工具:压缩 / 裁剪 / 九宫格 / 圆角 / 滤镜 / 拼图 / 水印,终生使用
前端
IT_陈寒6 小时前
Vue的v-if和v-for混用居然是个天坑
前端·人工智能·后端
天衍四九-6 小时前
【无标题】
前端·spring boot·mysql·nginx·docker
广州华水科技6 小时前
2026年单北斗GNSS变形监测系统推荐榜单,解锁GNSS位移监测新高度
前端