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 的工作原理!🎯

相关推荐
qq. 28040339847 小时前
CSS层叠顺序
前端·css
喝拿铁写前端7 小时前
SmartField AI:让每个字段都找到归属!
前端·算法
猫猫不是喵喵.7 小时前
vue 路由
前端·javascript·vue.js
烛阴8 小时前
JavaScript Import/Export:告别混乱,拥抱模块化!
前端·javascript
bin91538 小时前
DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例12,TableView16_12 拖拽动画示例
前端·javascript·vue.js·ecmascript·deepseek
GISer_Jing8 小时前
[Html]overflow: auto 失效原因,flex 1却未设置min-height &overflow的几个属性以及应用场景
前端·html
程序员黄同学8 小时前
解释 Webpack 中的模块打包机制,如何配置 Webpack 进行项目构建?
前端·webpack·node.js
拉不动的猪8 小时前
vue自定义“权限控制”指令
前端·javascript·vue.js
再学一点就睡8 小时前
浏览器页面渲染机制深度解析:从构建 DOM 到 transform 高效渲染的底层逻辑
前端·css
拉不动的猪9 小时前
刷刷题48 (setState常规问答)
前端·react.js·面试