访问模板引用
当我们需要直接访问底层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。这是因为在初次渲染前这个元素还不存在呢!
为模板引用标注类型 ?????
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的值;