Vue 3中的ref和template refs详解

在Vue 3中,ref和模板引用(template refs)是两个相关但不同的概念,它们在组合式API(Composition API)中扮演着重要角色。

ref - 响应式引用

ref是Vue 3中创建响应式数据的主要方式之一。

基本用法

import { ref } from 'vue'

// 创建一个响应式引用
const count = ref(0) // 访问或修改值需要使用.value
console.log(count.value) // 0
count.value++
console.log(count.value) // 1

特点

  1. 包装原始值ref可以将基本类型(如数字、字符串、布尔值)转换为响应式对象
  2. 需要使用.value:在JavaScript中访问或修改ref值时,必须使用.value属性
  3. 在模板中自动解包:在模板中使用时,Vue会自动解包ref,不需要写.value
<template>
<div>{{ count }}</div> <!-- 不需要.value -->
</template>

复杂数据结构

对于对象和数组,ref内部使用reactive来实现响应式:

const user = ref({
name: '张三',
age: 30
}) // 修改属性
user.value.age = 31

template refs - 模板引用

模板引用允许你直接访问DOM元素或组件实例。

Vue 2中的使用方式

在Vue 2中,我们通过this.$refs访问模板引用:

<template>
<div>
<input ref="inputElement">
<ChildComponent ref="childComponent"/>
</div>
</template> <script>
export default {
mounted() {
// 访问DOM元素
this.$refs.inputElement.focus() // 访问子组件实例
this.$refs.childComponent.someMethod()
}
}
</script>

Vue 3中的使用方式

在Vue 3的组合式API中,模板引用的使用方式发生了变化:

  1. 创建ref变量:首先创建一个ref变量
  2. 在模板中绑定:将这个ref变量绑定到元素或组件上
  3. 在组件挂载后访问:组件挂载后,ref变量的.value将包含对应的DOM元素或组件实例
<template>
<div>
<input ref="inputRef">
<ChildComponent ref="childComponentRef"/>
</div>
</template> <script setup>
import { ref, onMounted } from 'vue'
import ChildComponent from './ChildComponent.vue' // 创建模板引用
const inputRef = ref(null)
const childComponentRef = ref(null) onMounted(() => {
// 访问DOM元素
inputRef.value.focus() // 访问子组件实例
childComponentRef.value.someMethod()
})
</script>

动态模板引用(v-for中使用)

在循环中使用模板引用时,需要使用函数形式的ref:

<template>
<div>
<ul>
<li v-for="(item, i) in list" :key="i" :ref="el => { if (el) itemRefs[i] = el }">
{{ item }}
</li>
</ul>
</div>
</template> <script setup>
import { ref, onMounted, onBeforeUpdate } from 'vue' const list = ref(['苹果', '香蕉', '橙子'])
const itemRefs = ref([]) // 在更新前清空引用数组
onBeforeUpdate(() => {
itemRefs.value = []
}) onMounted(() => {
console.log(itemRefs.value) // DOM元素数组
})
</script>

示例:关于v-for生成的ref的复杂例子,Vue2+js移植到Vue3+TS

旧的Vue2+js程序:

<template>
<MixerCtrlItem v-if="konvaInitlizedFlag" v-for="(item, index) in inputBottomGroups" :key="index"
:ref="`col-${index}`" :x="0" :y="0" :parent="item" :deviceIp="deviceIp" :modelName="modelName"
:paramName="paramName" :index="index" :channel="this.colPageIndex * this.pageColCount + index"
:ctrlItemType="'mixer-input'" />
<MixerCtrlItem v-if="konvaInitlizedFlag" v-for="(item, index) in outputRightGroups" :key="index" :x="0" :y="0"
:ref="`row-${index}`" :parent="item" :deviceIp="deviceIp" :modelName="modelName" :paramName="paramName"
:index="index" :channel="this.rowPageIndex * this.pageRowCount + index" :ctrlItemType="'mixer-output'" />
<template v-if="konvaInitlizedFlag" v-for="(row, rowIndex) in centerContentGroupsMap" :key="rowIndex">
<MixerCtrlItem v-for="(item, colIndex) in row" :key="`${rowIndex}-${colIndex}`"
:ref="`row-${rowIndex}-col-${colIndex}`" :x="0" :y="0" :parent="item" :deviceIp="deviceIp"
:modelName="modelName" :paramName="paramName" :rowIndex="rowIndex" :colIndex="colIndex"
:channel="this.rowPageIndex * this.pageRowCount + rowIndex"
:extraData2="this.colPageIndex * this.pageColCount + colIndex" :ctrlItemType="'mixer-node'" />
</template>
</template>
// 使用到ref的位置示例,type获取细节不表
const refMap = {
'in-gain': `col-${channel}`,
'out-gain': `row-${channel}`,
'node-gain': `row-${channel}-col-${nodeInputChannel}`,
'in-btn': `col-${channel}`,
'out-btn': `row-${channel}`,
'node-btn': `row-${channel}-col-${nodeInputChannel}`,
}; const refName = refMap[type];
if (!refName) {
console.error('Unknown type:', type);
return null;
} // 处理数组型 ref(v-for 产生的)
const refs = this.$refs[refName];

在示例中,需要从Vue 2风格的$refs迁移到Vue 3的模板引用方式。具体步骤:

  1. 定义模板引用数组:
const inputGainRefs = ref([])
const outputGainRefs = ref([])
const nodeGainRefsMap = ref([])
  1. 在模板中使用这些引用:
<MixerCtrlItem
v-for="(item, index) in inputBottomGroups"
:key="index"
:ref="el => { if (el) inputGainRefs.value[index] = el }"
...其他属性
/>
  1. 在需要访问子组件时:
// 访问输入增益组件
inputGainRefs.value[0].someMethod() // 访问节点增益组件
nodeGainRefsMap.value[rowIndex][colIndex].someMethod()

总结

  1. ref:用于创建响应式数据,在JavaScript中需要使用.value访问
  2. template refs:用于访问DOM元素或组件实例
    • 在Vue 2中通过this.$refs访问
    • 在Vue 3中通过创建ref变量并在模板中绑定来实现
  3. 迁移策略
    • 创建对应的ref变量
    • 在模板中使用:ref绑定
    • 在组件挂载后通过.value访问实际元素或组件

这种方式不仅符合Vue 3的组合式API设计理念,还提供了更好的类型推断支持,特别是在使用TypeScript的项目中。

Vue 3中的ref和template refs详解(含Vue2迁移到Vue3方法)的更多相关文章

  1. Vue 标签中的ref属性和refs

    ref: ref 被用来给元素或子组件注册引用信息.引用信息将会注册在父组件的 $refs 对象上.如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素:如果用在子组件上,引用就指向组件. ...

  2. vue.js选择if(条件渲染)详解

    vue.js选择if(条件渲染)详解 一.总结 一句话总结: v-if <!DOCTYPE html> <html lang="en"> <head& ...

  3. vue.js循环for(列表渲染)详解

    vue.js循环for(列表渲染)详解 一.总结 一句话总结: v-for <ul id="example-1"> <li v-for="item in ...

  4. Vue通信、传值的多种方式,详解

    Vue通信.传值的多种方式,详解 转自:https://blog.csdn.net/qq_35430000/article/details/79291287 一.通过路由带参数进行传值 ①两个组件 A ...

  5. vue高级进阶( 二 ) 8种组件通信详解

      vue高级进阶( 二 ) 8种组件通信详解 猛兽总是独行,牛羊才成群结队. -------鲁迅 vue组件通信的重要性无需多言...但是你肯定没有全部掌握,所以这第二篇文章应运而生 props和$ ...

  6. 【转】angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

  7. angularjs指令中的compile与link函数详解

    这篇文章主要介绍了angularjs指令中的compile与link函数详解,本文同时诉大家complie,pre-link,post-link的用法与区别等内容,需要的朋友可以参考下   通常大家在 ...

  8. Vue不兼容IE8原因以及Object.defineProperty详解

    Vue不兼容IE8原因以及Object.defineProperty详解 原因概述: Vue.js使用了IE8不能模拟的ECMAScript5特性. Vue.js支持所有兼容ES5的浏览器. Vue将 ...

  9. Java中堆内存和栈内存详解2

    Java中堆内存和栈内存详解   Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...

  10. Python中操作mysql的pymysql模块详解

    Python中操作mysql的pymysql模块详解 前言 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而后者不支持 ...

随机推荐

  1. PERT 图表教程

    (翻译自: PERT Chart Tutorial) PERT 图表 是(程序评估和审查技术)的首字母缩写.PERT 图是一种项目管理工具,用于在项目中安排.组织和协调任务.它基本上是一种分析完成给定 ...

  2. Spark - [03] 资源调度模式

    题记部分 一.Local模式 1.1.概述 Local模式就是运行在一台计算机上的模式,通常就是用于在本机上练手和测试的. 可以通过以下几种方式设置Master (1)local:所欲计算都运行在一个 ...

  3. DataX - [01] 概述

      DataX是阿里巴巴集团内被广泛使用的离线数据同步工具/平台.实现包括MySQL.Oracle.SQLServer.PostgreSQL.HDFS.Hive.ADS.HBase.TableStor ...

  4. MySQL - [09] 正则表达式

    转载:https://mp.weixin.qq.com/s/7RavuYGs9SthX2pxGJppqw select * from t1 where name rlike '^[a-zA-Z]+$' ...

  5. 开源一款DDS信号发生扩展板-FreakStudio多米诺系列

    原文链接: FreakStudio的博客 摘要 信号发生扩展板通过SPI接口生成可调频率和幅度的正弦波.方波和三角波,频率小于1MHz.支持幅度调节,提供原始和6倍放大输出接口.配备5阶低通滤波器.噪 ...

  6. 获取Typora激活码的方法主要有以下几种

    ‌官方购买‌:访问Typora官网下载Typora软件.请注意,官网下载版本需购买激活,否则仅有15天试用期.购买费用为89元‌ 1. ‌使用激活工具‌:可以通过下载特定的激活工具来获取激活码.具体步 ...

  7. Towards Accurate Alignment in Real-time 3D Hand-Mesh Reconstruction论文解读

    Towards Accurate Alignment in Real-time 3D Hand-Mesh Reconstruction论文解读 这是发表在ICCV2021的一篇文章,主要的工作内容是R ...

  8. Pydantic递归模型深度校验36计:从无限嵌套到亿级数据的优化法则

    title: Pydantic递归模型深度校验36计:从无限嵌套到亿级数据的优化法则 date: 2025/3/26 updated: 2025/3/26 author: cmdragon excer ...

  9. IntelliJ IDEA 社区版没有 Spring Initializr

    RT 解决办法 打开文件 - 设置 - 插件 输入 Spring 找到插件 Spring Assistant 并安装 下载可能会需要一点点时间. 重启 IDEA 后,新建项目就可以看见 Spring ...

  10. Codeforces Round 971 (Div. 4)

    C. The Legend of Freya the Frog 因为是从x开始跳,贪心的取肯定是直接用max(a,b)/d向上取整然后再乘2,但是要注意,如果再x到达之前,y已经是到达了,也就是某次以 ...