VUE:模板引用(Template Ref)

什么是模板引用

模板引用(Template Ref) 是 Vue 提供的一种机制,允许我们在 JavaScript 中直接获取模板中的 DOM 元素组件实例 的引用。

基本语法

<template>
    <!-- 在元素/组件上添加 ref 属性 -->
    <div ref="myDiv">这是一个div元素</div>
    <ChildComponent ref="myChild" />
</template>

<script setup>
import { ref, onMounted } from 'vue'

// 声明与 ref 同名的变量
const myDiv = ref(null)      // 用于存储 DOM 元素
const myChild = ref(null)    // 用于存储组件实例

onMounted(() => {
    // 访问 DOM 元素
    console.log(myDiv.value)           // <div>这是一个div元素</div>
    console.log(myDiv.value.innerText) // "这是一个div元素"
    
    // 访问组件实例
    console.log(myChild.value)         // ChildComponent 的实例
})
</script>

引用存储的是什么?

// 当 ref 用在普通元素上
<div ref="divRef"></div>
// divRef.value 存储的是: HTMLElement 对象
// 例如:HTMLDivElement, HTMLInputElement, HTMLImageElement 等

// 当 ref 用在组件上
<Child ref="childRef"></Child>
// childRef.value 存储的是: 组件的实例对象
// 包含组件的所有属性和方法(除非被 defineExpose 限制)

引用赋值的时机

// 生命周期中的 ref 状态
beforeCreate()  // ❌ ref 不存在
created()       // ❌ ref 不存在(模板尚未编译)
beforeMount()   // ❌ ref 不存在(尚未渲染到DOM)
mounted()       // ✅ ref 已赋值(DOM渲染完成)
updated()       // ✅ ref 更新(DOM更新后)
beforeUnmount() // ✅ ref 仍存在
unmounted()     // ❌ ref 被重置为 null

详细使用场景

操作原生 DOM(uni-app不可以)

uni-app 环境<input ref="inputRef">得到的 不是原生 DOM,而是 uni-app 的组件实例,所以inputRef.value.focus()就会报错:focus is not a function

因此,在 uni-app 里,不要用 ref 操作 DOM,要用 组件属性(例如 focus)控制行为

但在 uni-app 中,input 实际上是跨平台组件:

<input>
   ↓
小程序组件 / App组件 / H5组件

所以:ref → 组件实例

而不是:ref → DOM

因此没有:focus()

父组件调用子组件方法

<!-- 子组件 Child.vue -->

<template>
  <view>我是子组件</view>
</template>

<script setup>
function sayHello(){
  console.log("子组件方法被调用")
}

// 必须暴露方法
defineExpose({
  sayHello
})
</script>



<!-- 父组件 -->
<template>
  <view>
    <Child ref="childRef"/>
    <button @click="callChild">调用子组件方法</button>
  </view>
</template>

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const childRef = ref(null)

function callChild(){
  childRef.value.sayHello()
}
</script>

Vue 内部的工作原理(简化版)

// Vue 内部的工作原理(简化版)

// 1. 你声明变量
const childRef = ref(null)

// 2. Vue 编译模板时,发现有 ref="childRef"
<template>
  <view>
    <Child ref="childRef"/>
    <button @click="callChild">调用子组件方法</button>
  </view>
</template>

// 3. Vue 内部建立映射表
const refRegistry = {
    "childRef": childRef  // 将 ref 名与你声明的变量关联
}

// 4. 当 DOM 渲染完成后
const element = document.createElement('<view>')
refRegistry["childRef"].value = element  // 自动赋值给 .value

// 5. 当组件卸载时
refRegistry["childRef"].value = null  // 自动重置为 null

初始值

为什么必须是 null 不是 undefined?

// 为什么不能用 undefined?
const childRef = ref(undefined)  // ❌ 技术上可行但不符合规范

// Vue 官方要求使用 null 的原因:
// 1. null 表示"有意的空值"(intentional absence)
// 2. undefined 表示"未定义"(uninitialized)
// 3. null 更适合表示"尚未挂载的引用"

×

喜欢就点赞,疼爱就打赏