vue3模板引用介绍

本文介绍了Vue3中ref属性的使用,包括如何在组件挂载后访问DOM元素,模板引用的注意事项,以及在v-for循环和函数模板中的应用。重点讲解了ref的类型标注和组件间通信的方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

访问模板引用

当我们需要直接访问底层DOM元素时,vue3中我们可以使用特殊的ref属性;

ref 是一个特殊的 attribute,和 v-for 章节中提到的 key 类似。它允许我们在一个特定的 DOM 元素或子组件实例被挂载后,获得对它的直接引用。

//设置页面加载完成当前input直接获取焦点
//vue3 index.vue
<script setup>
import { ref, onMounted } from 'vue'

// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const inputRef= ref(null)

onMounted(() => {
  inputRef.value.focus()
})
</script>

<template>
  <input ref="inputRef" />
</template>

只可以在组件挂载后才能访问模板引用。如果你想在模板中的表达式上访问 input,在初次渲染时会是 null。这是因为在初次渲染前这个元素还不存在呢!

侦听模板引用ref的变化

watchEffect(() => {
  if (input.value) {
    inputRef.value.focus()
  } else {
    // 此时还未挂载,或此元素已经被卸载(例如通过 v-if 控制)
  }
})

为模板引用标注类型

官网参考
在 Vue 3.5 和 @vue/language-tools 2.1 (为 IDE 语言服务和 vue-tsc 提供支持) 中,在单文件组件中由 useTemplateRef() 创建的 ref 类型可以基于匹配的 ref attribute 所在的元素自动推断为静态类型。

在无法自动推断的情况下,仍然可以通过泛型参数将模板 ref 转换为显式类型。

const inputRef = useTemplateRef<HTMLInputElement>(null)

注意为了严格的类型安全,有必要在访问 el.value 时使用可选链或类型守卫。这是因为直到组件被挂载前,这个 ref 的值都是初始的 null,并且在由于 v-if 的行为将引用的元素卸载时也可以被设置为 null。

v-for中的模板引用

版本要求:V3.2.25及以上版本

<script setup>
import { ref, onMounted } from 'vue'
const itemData=ref([
	{id:12,name:'第一列'},
	{id:13,name:'第二列'},
	{id:21,name:'第三列'}
])
const itemRefs = ref([]);
onMounted(()=>{
	console.log('itemRefs',itemRefs.value);
	// console.log('innerText',itemRefs.value.map(i => i.innerText));
	console.log('innerText',itemRefs.value.map(i => i.textContent));
	//为三个li设置style和类
	itemRefs.value[0].style = "color:green";
	itemRefs.value[1].style = "color:#f00";
	itemRefs.value[2].setAttribute("class","fontW");
})
</script>

<template>
<ul>
	<li v-for="(item,index) in itemData" :key="item.id" ref="itemRefs">{{index}}-{{item.name}}</li>
</ul>
</template>

ref 数组并不保证与源数组相同的顺序

函数模板引用

除了使用字符串值作名字,ref attribute 还可以绑定为一个函数,会在每次组件更新时都被调用。

<input :ref="(el) => { /* 将 el 赋值给一个数据属性或 ref 变量 */ }">

注意我们这里需要使用动态的 :ref 绑定才能够传入一个函数。当绑定的元素被卸载时,函数也会被调用一次,此时的 el 参数会是 null。你当然也可以绑定一个组件方法而不是内联函数。

<script setup>
import { ref, onMounted,nextTick } from 'vue'
const inputVal2 = ref();
const inputVal3 = ref(15);

function inputChange(val,el){
	/*不使用nextTick时,首次获取不到input的value值,但不报错*/
	nextTick(()=>{
		console.log('val',val);
		console.log('el',el.value);
	})
}
</script>
<template>
<div :ref="el=>{ console.log('测试el',el.innerText); }">测试</div>
<input :ref="el=> { console.log('输入值',el.value); }" v-model="inputVal2" placeholder="请输入内容" />
<!-- 定义一个inputChange函数,传递一个固定参数5和el -->
<input :ref="el=> inputChange(5,el)" v-model="inputVal3" placeholder="请输入内容" />
</template>

组件上的ref

模板中引入一个子组件,子组件使用ref时,获取的为组件实例

//父组件
<script setup>
import { ref, onMounted } from 'vue'
import MyComponent from '@/components/MyComponent.vue'

const btnC = ref('#fff');
const myComRef = ref(null);

onMounted(() => {
	// myComRef.value 是 <MyComponent /> 组件的实例
 	console.log(myComRef.value); 
})
</script>

<template>
	<MyComponent ref="myComRef" class="className" :btnColor='btnC'></MyComponent>
</template>

如果一个子组件使用的是选项式 API 或没有使用 < script setup>,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。

子组件使用< script setup >时,子组件默认私有,父组件无法获取子组件任何内容;须通过 defineExpose 宏显式暴露;

//MyComponent 子组件
<template>
	<button :style="{color:btnColor}" @click="btnClick">{{btnName}}</button>
</template>

<script setup>
	// const props = defineProps(['btnColor'])
	defineProps({
		btnColor: String
	})
	import { ref } from 'vue'
	// const btnColor = ''
	const btnName = ref('子组件按钮');
	function btnClick(){
		console.log('子组件点击事件');
	}
	defineExpose({
		btnName
	})
</script>

<style scoped>
	.red{
		color: #f00;
		font-weight: 700;
	}
</style>

父组件可通过myComRef.value.btnName获取子组件btnName的值;

为组件的模板引用标注类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值