当前位置: 首页 > news >正文

ref 应用于对象类型的一个案例

一个案例:

<template><el-form :model="loginForm" :rules="rules"ref="ruleForm"  class="login-container" label-position="left"label-width="80px" v-loading="loading"  status-icon><el-text class="mx-1" size="large" >系统登录</el-text><div style="margin: 20px" /><el-form-item label="用户名" prop="userName"><el-input v-model="loginForm.userName" placeholder="用户名"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input  type="password" v-model="loginForm.password" placeholder="密码"></el-input></el-form-item><el-form-item><el-button type="primary" @click.native.prevent="submitClick">Login</el-button></el-form-item></el-form>	
</template><script setup>
import { ref } from "vue";
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import { postReq } from '../utils/api'
import { ElMessageBox } from 'element-plus'
//导入用户仓库
import { useUserStore } from '../store/user.js'//路由
const router = useRouter()
//获取用户仓库对象
const userStore=useUserStore()
const loginForm=ref({userName: 'admin',password: 'admin123'
})const rules=ref({userName: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' }],password: [{ required: true, message: '请输入密码', trigger: 'blur' },{ min: 6, max: 16, message: '长度在 6 到 16 个字符', trigger: 'blur' }]
})// 提交表单数据的函数
const submitClick=()=>{postReq("/user/login",loginForm.value).then(resp=>{if(resp.data.result){let u=resp.data.data;u.token=resp.data.token;u.isAuth=true;//console.log(u);userStore.setAuthenticated(u)//登录成功后跳转到指定页面router.push('/home')}else{ElMessageBox.alert(resp.data.errMsg, '提示',{})}})
}</script><style>.login-container {border-radius: 15px;background-clip: padding-box;margin: 180px auto;width: 350px;padding: 35px 35px 15px 35px;background: #fff;border: 1px solid #eaeaea;box-shadow: 0 0 25px #cac6c6;}.login_title {margin: 0px auto 40px auto;text-align: center;color: #505458;}.login_remember {margin: 0px 0px 35px 0px;text-align: left;}	
</style>

我们先看看,在 Vue3 中,ref() 和 reactive()的 的区别。当 ref() 应用于对象时,其内部实现和响应式机制与直接使用 reactive() 有本质区别,但最终效果有相似之处。以下是详细解析:

1. ref() 与 reactive() 的核心区别

  • ref():创建一个响应式引用对象,内部通过 Object.defineProperty 或 Proxy 拦截 .value 的读写操作。

    • 无论初始值是基本类型(如 ref(0))还是对象(如 ref({})),ref 始终是一个包含 .value 属性的对象。
    • 当值为对象时,Vue 会自动将该对象转为 reactive 代理,但包裹层仍是 ref
  • reactive():直接创建一个深层响应式的对象代理,无需 .value 访问。

    • 只能用于对象或数组,不能用于基本类型。

2. ref() 应用于对象时的内部机制

当你使用 ref() 包裹对象时:

javascript

const loginForm = ref({userName: 'admin',password: 'admin123'
});

  • 外层结构loginForm 是一个 ref 对象,具有 .value 属性。
  • 内层值loginForm.value 是一个通过 reactive() 创建的响应式代理对象。
  • 响应式原理
    1. 访问 loginForm.value.userName 时,先触发 ref 的 .value 的 getter,再触发内部 reactive 对象的 userName 的 getter
    2. 修改 loginForm.value.password = 'newPassword' 时,触发内部 reactive 对象的 setter,通知依赖更新。

关键区别ref 是一个 “容器”,而 reactive 是容器中的 “内容”。

3. 与直接使用 reactive() 的对比

javascript

// 方式1:使用 ref() 包裹对象
const loginFormRef = ref({userName: 'admin',password: 'admin123'
});// 方式2:直接使用 reactive()
const loginFormReactive = reactive({userName: 'admin',password: 'admin123'
});

  • 访问方式

    • loginFormRef.value.userName(需通过 .value)。
    • loginFormReactive.userName(直接访问)。
  • 解构后响应性

    • const { userName } = loginFormRef.valueuserName 是普通变量,无响应性。
    • const { userName } = loginFormReactiveuserName 失去响应性(需用 toRefs() 保持)。
  • 类型转换

    • ref 对象可通过 toRefs(loginFormRef.value) 转为响应式引用。
    • reactive 对象可通过 toRef(loginFormReactive, 'userName') 转为单个属性的响应式引用。

4. 应用场景选择

  • 使用 ref() 包裹对象

    • 当需要在组合式函数中返回对象,且保持统一的 .value 访问模式。
    • 当需要在模板中通过 v-model 绑定整个对象(如表单组件)。
  • 直接使用 reactive()

    • 当不需要 .value 语法,希望代码更简洁。
    • 当对象结构复杂,需要深层响应式,且无需解构。

5. 小结

  • ref() 包裹对象时:外层是 ref 容器,内层是 reactive 代理,本质是 ref + reactive 的组合
  • 直接使用 reactive() 时:对象本身就是响应式代理,无需额外容器。

我们在模版中 这样使用的:

你们可以看到 我们没有用前文提到的 loginFormRef.valueuserName   去访问啊,错了吗?

没错哟~~~

  1. 模板中v-model="loginForm.userName" 正确,因为 Vue 自动解包 loginForm 为 loginForm.value
  2. JavaScript 中postReq("/user/login", loginForm.value) 正确,因为必须显式访问 .value

如果使用 reactive,则代码需要改为:

// 使用 reactive
const loginForm = reactive({userName: 'admin',password: 'admin123'
});// 模板中仍然直接访问
<el-input v-model="loginForm.userName">// JavaScript 中直接使用
postReq("/user/login", loginForm); // 无需 .value

我们项目中主要应用的是ref,大部分项目也是这样的,原因是:

  1. 统一访问模式:所有状态都用 .value,降低复杂度。
  2. 类型安全:TypeScript 推导更直观,减少类型错误。
  3. 组合式适配:更符合 Vue3 的函数式设计理念。组合函数,后面有空再讲。

相关文章:

  • webgl(three.js 与 cesium 等实例应用)之浏览器渲染应用及内存释放的关联与应用
  • go-carbon v2.6.8 发布,轻量级、语义化、对开发者友好的 golang 时间处理库
  • 在 Flutter 项目中iOS 的 App 图标和 App 名称 的设置
  • Spring依赖注入的四种方式(面)
  • 集装箱残损识别系统如何检测残损?它的识别率能达到多少?
  • MySQL 索引学习笔记
  • OpenCV CUDA模块图像变形------对图像进行下采样操作函数pyrDown()
  • 基于Node.js的线上教学系统的设计与实现(源码+论文+调试+安装+售后)
  • Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型时序预测对比
  • LSTM助力迁移学习!深度学习架构性能提升,准确率达到99.91%!
  • 【无标题】六边形铺砖拓扑模型的深度解析:从几何结构到量子优势
  • 【机器学习】Teacher-Student框架
  • 使用freemarker模板 生成 word文档
  • 【论文阅读笔记】高光反射实时渲染新突破:3D Gaussian Splatting with Deferred Reflection 技术解析
  • Spring MVC 常用请求处理注解总结
  • 三轴云台之运动控制系统篇
  • uniapp——input 禁止输入 ,但是可以点击(禁用、可点击)
  • php列表头部增加批量操作按钮,多选订单数据批量微信退款(含微信支付SDK)
  • Kafka入门:解锁核心组件,开启消息队列之旅
  • 如何“下载安转Allure”?
  • 合山网站建设/如何建造自己的网站
  • 个人建站的app哪里有卖/外链系统
  • 通过云主机建设网站/友链互换平台推荐
  • b2b网站做排名是什么意思/外贸推广具体是做什么
  • 湖南省金力电力建设有限公司 网站/设计网络营销方案
  • btoc的网站/seo课程培训中心