news 2026/7/15 4:37:48

掌握Vue3 第六章(Ref全家桶实战与避坑指南)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
掌握Vue3 第六章(Ref全家桶实战与避坑指南)

1. Ref基础:从入门到精通

Vue3的ref函数可以说是响应式编程的基石。我第一次接触ref时,也被它简洁而强大的特性所吸引。ref的核心作用就是将一个普通的JavaScript值转换为响应式对象,这个对象有一个.value属性指向原始值。

import { ref } from 'vue' // 基本用法 const count = ref(0) console.log(count.value) // 0 // 修改值 count.value++ console.log(count.value) // 1

在实际项目中,我经常用ref来处理表单输入。比如下面这个用户登录场景:

const username = ref('') const password = ref('') const handleLogin = () => { if(username.value && password.value) { // 登录逻辑 } }

这里有个新手容易踩的坑:在模板中使用ref时不需要.value,但在script中必须使用.value。我刚开始用Vue3时就经常忘记写.value,导致代码不工作。

ref对对象和数组的处理也很智能。它会递归地将所有嵌套属性都转为响应式:

const user = ref({ name: '张三', address: { city: '北京' } }) // 修改嵌套属性 user.value.address.city = '上海' // 这个修改也是响应式的

2. 模板引用:操作DOM的利器

模板引用是ref的另一个重要用途。通过给DOM元素添加ref属性,我们可以在组件挂载后直接操作DOM元素。这在集成第三方库或实现特定UI效果时特别有用。

<template> <input ref="inputRef" type="text"> </template> <script setup> import { ref, onMounted } from 'vue' const inputRef = ref(null) onMounted(() => { // 组件挂载后,inputRef.value就是真实的DOM元素 inputRef.value.focus() }) </script>

我在一个项目中需要实现图片懒加载,就是通过模板引用结合IntersectionObserver实现的:

const imgRef = ref(null) onMounted(() => { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if(entry.isIntersecting) { entry.target.src = entry.target.dataset.src observer.unobserve(entry.target) } }) }) observer.observe(imgRef.value) })

模板引用也可以用在子组件上,这时ref.value获取的是子组件的实例:

<template> <ChildComponent ref="childRef" /> </template> <script setup> const childRef = ref(null) // 调用子组件方法 childRef.value.someMethod() </script>

3. shallowRef:性能优化的秘密武器

shallowRef是ref的"轻量版",它只跟踪.value的变化,不会深度转换嵌套对象。这在处理大型对象时能显著提升性能。

import { shallowRef } from 'vue' const bigData = shallowRef({ // 包含大量数据的复杂对象 }) // 直接替换value会触发响应式更新 bigData.value = newValue // 修改嵌套属性不会触发更新 bigData.value.nested.prop = 'new value' // 不会触发更新!

我在开发一个数据可视化项目时,遇到了性能问题。数据量很大但很少需要深度更新,换成shallowRef后性能提升了约30%。

如果需要强制更新shallowRef的值,可以使用triggerRef:

import { shallowRef, triggerRef } from 'vue' const state = shallowRef({ count: 0 }) // 修改嵌套属性 state.value.count++ // 手动触发更新 triggerRef(state)

4. customRef:打造专属响应式逻辑

customRef允许我们自定义ref的行为,这在需要实现防抖、节流等高级功能时特别有用。

下面是一个防抖ref的实现:

import { customRef } from 'vue' function debouncedRef(value, delay = 500) { let timer return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timer) timer = setTimeout(() => { value = newValue trigger() }, delay) } } }) } // 使用示例 const searchText = debouncedRef('', 300)

我在开发搜索功能时就用到了这个自定义ref。用户连续输入时不会立即触发搜索,而是在停止输入300ms后才执行搜索请求,既提升了性能又改善了用户体验。

5. Ref与Reactive的抉择

很多开发者纠结该用ref还是reactive。根据我的经验,ref更适合处理基本类型和需要替换整个对象的情况,而reactive更适合处理不需要替换的复杂对象。

// 适合用ref的场景 const count = ref(0) const user = ref({ name: '张三' }) // 适合用reactive的场景 const form = reactive({ username: '', password: '' })

Vue官方推荐优先使用ref,因为它的行为更一致,而且在组合式函数中更容易传递。我在项目中也是主要使用ref,只有在处理紧密相关的多个属性时才会考虑reactive。

6. 实战中的常见陷阱

在使用ref的过程中,我踩过不少坑,这里分享几个常见的:

  1. 忘记.value:在script中修改ref值时容易忘记写.value
const count = ref(0) count++ // 错误!应该是count.value++
  1. 解构失去响应性:直接解构ref会失去响应性
const state = ref({ count: 0 }) const { count } = state.value // count不是响应式的
  1. 异步更新问题:在同一个事件循环中多次修改ref,Vue会合并更新
const count = ref(0) count.value++ count.value++ console.log(count.value) // 2,但DOM可能只更新一次
  1. 模板引用未挂载:在onMounted之前访问模板引用会是null
const inputRef = ref(null) console.log(inputRef.value) // null,因为组件还没挂载

7. 性能优化技巧

经过多个项目的实践,我总结了一些ref性能优化的经验:

  1. 对于大型不可变数据,使用shallowRef
  2. 避免在渲染函数中创建新的ref
  3. 合理使用computed减少不必要的ref更新
  4. 对于频繁更新的ref,考虑使用customRef实现节流
  5. 在v-for中使用ref时,考虑使用函数ref避免性能问题
// 不好的做法 <div v-for="item in list" :ref="itemRefs"></div> // 更好的做法 <div v-for="item in list" :ref="el => { if(el) itemRefs[item.id] = el }"></div>

8. TypeScript支持

Vue3对TypeScript的支持非常完善,ref也能很好地与TS配合。我们可以为ref指定明确的类型:

const count = ref<number>(0) // 明确指定为number类型 interface User { name: string age: number } const user = ref<User>({ name: '张三', age: 20 })

对于模板引用,我们也可以指定具体的元素类型:

const inputRef = ref<HTMLInputElement | null>(null)

在子组件引用时,可以使用InstanceType来获取组件实例类型:

const childRef = ref<InstanceType<typeof ChildComponent> | null>(null)

9. 组合式函数中的Ref

在编写组合式函数时,ref是最常用的工具之一。它允许我们在函数之间共享响应式状态:

// useCounter.ts export function useCounter(initialValue = 0) { const count = ref(initialValue) const increment = () => count.value++ const decrement = () => count.value-- return { count, increment, decrement } } // 在组件中使用 const { count, increment } = useCounter()

我经常用这种模式来封装可复用的业务逻辑,比如表单验证、数据获取等。ref的这种特性让代码组织变得更加灵活。

10. 与其他特性的配合

ref可以很好地与Vue的其他特性配合使用。比如与watch一起使用:

const count = ref(0) watch(count, (newVal, oldVal) => { console.log(`count从${oldVal}变为${newVal}`) })

与v-model配合使用:

const text = ref('') <template> <input v-model="text" /> </template>

在开发复杂组件时,这种组合使用可以大大简化代码逻辑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/15 4:34:12

小米智能音箱Pro体验:平衡音质与智能交互的家庭枢纽

去年我帮朋友选蓝牙音箱&#xff0c;他提了个挺典型的需求&#xff1a;既要能在家听音乐时“有点感觉”&#xff0c;又要能语音控制智能家居&#xff0c;预算还不能太高。市面上很多音箱要么音质还行但智能功能简陋&#xff0c;要么智能交互流畅但听歌像听收音机。最后我们选了…

作者头像 李华
网站建设 2026/7/15 4:32:13

记录:hbuildx 无线真机调试,公司网络无法连接问题

1.手机连接电脑热点&#xff0c;开发者选项中打开无线调试&#xff0c;在页面选择配对码连接&#xff0c;弹出端口和code码 2.电脑端端打开对应目录&#xff0c;例&#xff1a;plugins\launcher-tools\tools\adbs&#xff0c;打开cmd&#xff0c;执行&#xff1a;adb kill-serv…

作者头像 李华
网站建设 2026/7/15 4:31:53

Kilo Code接入GLM-4.6本地补全实战指南

1. 项目概述&#xff1a;为什么“让Kilo Code支持GLM-4.6补全”不是一句口号&#xff0c;而是开发者真实痛点的精准切口Kilo Code——这个在中文开发者圈里悄然崛起的轻量级VS Code插件&#xff0c;最近半年被大量前端、Python初学者和教育场景用户反复提及。它不走Copilot那种…

作者头像 李华
网站建设 2026/7/15 4:31:25

DRA75x引脚配置实战:从GMAC、GPIO到eMMC的硬件设计与软件避坑指南

1. DRA75x引脚功能配置&#xff1a;嵌入式硬件设计的基石在嵌入式硬件开发中&#xff0c;尤其是基于德州仪器&#xff08;TI&#xff09;这类高性能异构多核处理器的项目中&#xff0c;引脚功能配置往往是硬件工程师和底层驱动工程师面临的第一个硬骨头。你可能已经拿到了DRA75…

作者头像 李华
网站建设 2026/7/15 4:30:46

Weknora AI知识库问答系统检索指标测试方法

Weknora AI知识库问答系统检索指标测试方法 一、测试前置条件 1. 系统环境与技术栈确认 Weknora系统测试环境与生产配置一致&#xff0c;目标知识库已完成结构感知分块&#xff0c;所有文档块通过text-embedding-v4模型生成向量&#xff0c;存储于pgvectorscale向量数据库向量库…

作者头像 李华
网站建设 2026/7/15 4:30:11

IP与IK防护:厂家必须知道的可靠性真相

先讲一个让厂家心疼的真实案例。有一家做户外智能锁的厂家&#xff0c;产品送测时&#xff0c;IPX4&#xff08;防溅水&#xff09;和IK08&#xff08;防冲击&#xff09;都单独过了。结果装到客户门上&#xff0c;一个台风天&#xff0c;雨水顺着锁体缝隙渗进去&#xff0c;电…

作者头像 李华