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 用于创建一个响应式引用 ,可以包装基本类型(如 numberstring)或对象:

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. 适用场景
    • 基本类型的响应式数据(如 numberstring)。
    • 存储 DOM 引用(<div ref="el">)。
    • 需要明确 .value 访问的情况(更可控)。

🚀 进阶建议:

  • 如果想深入 Vue 响应式系统,可以研究 effecttracktrigger 的源码。
  • 在组合式 API 中,refreactive 可以结合使用。

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

相关推荐
xixixin_几秒前
【uniapp】uni.setClipboardData 方法失效 bug 解决方案
java·前端·uni-app
狂炫一碗大米饭1 分钟前
大厂一面,刨析题型,把握趋势🔭💯
前端·javascript·面试
工业互联网专业5 分钟前
基于springboot+vue的校园二手物品交易平台
java·vue.js·spring boot·毕业设计·源码·课程设计·校园二手物品交易平台
星空寻流年7 分钟前
css3新特性第五章(web字体)
前端·css·css3
加油乐13 分钟前
JS计算两个地理坐标点之间的距离(支持米与公里/千米)
前端·javascript
小小小小宇13 分钟前
前端在 WebView 和 H5 环境下的缓存问题
前端
懒羊羊我小弟17 分钟前
React JSX 语法深度解析与最佳实践
前端·react.js·前端框架
冷冷清清中的风风火火21 分钟前
关于敏感文件或备份 安全配置错误 禁止通过 URL 访问 Vue 项目打包后的 .gz 压缩文件
前端·vue.js·安全
小行星12533 分钟前
前端根据后端返回的excel二进制文件流进行导出下载
前端·excel
Moment42 分钟前
前端远程面试全记录:项目、思维、管理一个不落 😔😔😔
前端·javascript·面试