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
特点
- 包装原始值:
ref
可以将基本类型(如数字、字符串、布尔值)转换为响应式对象 - 需要使用.value:在JavaScript中访问或修改ref值时,必须使用
.value
属性 - 在模板中自动解包:在模板中使用时,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中,模板引用的使用方式发生了变化:
- 创建ref变量:首先创建一个ref变量
- 在模板中绑定:将这个ref变量绑定到元素或组件上
- 在组件挂载后访问:组件挂载后,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的模板引用方式。具体步骤:
- 定义模板引用数组:
const inputGainRefs = ref([]) const outputGainRefs = ref([]) const nodeGainRefsMap = ref([])
- 在模板中使用这些引用:
<MixerCtrlItem v-for="(item, index) in inputBottomGroups" :key="index" :ref="el => { if (el) inputGainRefs.value[index] = el }" ...其他属性 />
- 在需要访问子组件时:
// 访问输入增益组件 inputGainRefs.value[0].someMethod() // 访问节点增益组件 nodeGainRefsMap.value[rowIndex][colIndex].someMethod()
总结
- ref:用于创建响应式数据,在JavaScript中需要使用
.value
访问 - template refs:用于访问DOM元素或组件实例
- 在Vue 2中通过
this.$refs
访问 - 在Vue 3中通过创建ref变量并在模板中绑定来实现
- 在Vue 2中通过
- 迁移策略:
- 创建对应的ref变量
- 在模板中使用
:ref
绑定 - 在组件挂载后通过
.value
访问实际元素或组件
这种方式不仅符合Vue 3的组合式API设计理念,还提供了更好的类型推断支持,特别是在使用TypeScript的项目中。
原创作者: dandelion-000-blog 转载于: https://www.cnblogs.com/dandelion-000-blog/p/18867929