考察点分析

该题目主要考查以下核心能力维度:

  1. Vue响应式系统理解:掌握组件实例与DOM元素访问的正确姿势,避免直接操作DOM破坏响应式原则
  2. 组件通信机制:理解跨组件访问的官方推荐模式
  3. 组合式API适应能力:展示从选项式API到组合式API的迁移认知

具体技术评估点:

  • ref属性的两种使用场景(DOM元素/组件实例)
  • $refs集合的初始化时机与响应式特性
  • 组合式API中模板引用的处理方式
  • expose()方法在组件封装中的作用
  • TypeScript类型推导在模板引用中的应用

技术解析

关键知识点

模板引用 > 组件实例方法暴露 > 组合式API适配

原理剖析

  1. 模板引用机制:通过ref特殊属性创建直接访问入口。Vue在组件挂载时,将DOM元素/组件实例自动绑定到this.$refs对象,该过程发生在mounted生命周期后

  2. 响应式脱敏$refs本身并非响应式对象。当使用v-for时,引用会转换为数组形式,但数组元素仍保持非响应式特性

  3. 组合式API变化

  // 声明与模板中ref同名的响应式引用
const childRef = ref(null)

// 必须return才能在模板中访问
return { childRef }
  

需注意:

  • 引用值在组件挂载后才可用
  • 需使用expose显式暴露子组件方法
  • 模板引用与响应式ref共享命名空间

常见误区

  • 在created阶段尝试访问$refs
  • 误以为refs变化会触发视图更新
  • v-for中使用索引访问动态引用未做空值校验
  • 组合式API中忘记return模板引用

问题解答

Vue提供了两种安全方式访问子组件或DOM元素:

  1. ref属性
  • 在DOM元素上使用<div ref="domRef">,通过this.$refs.domRef访问原生DOM
  • 在子组件上使用<Child ref="childRef">,获取组件实例并调用其暴露的方法
  1. $refs工作机制
  • 在组件渲染后填充引用
  • 非响应式对象,不可用于模板绑定
  • v-for循环中返回引用数组

组合式API变化要点:

  1. 使用同名响应式ref变量替代this.$refs
  2. 需通过expose方法显式暴露子组件方法
  3. 模板引用需在setup()中声明并return
  4. TypeScript需手动标注引用类型

解决方案

选项式API示例

  // 子组件
export default {
  methods: {
    doSomething() {
      // 组件方法
    }
  }
}

// 父组件模板
<template>
  <ChildComponent ref="child" />
  <button ref="btn">Submit</button>
</template>

<script>
export default {
  mounted() {
    this.$refs.child.doSomething() // 访问子组件
    this.$refs.btn.focus() // 操作DOM
    
    // 动态引用处理
    if (Array.isArray(this.$refs.child)) {
      this.$refs.child[0].doSomething()
    }
  }
}
</script>
  

组合式API示例

  // 子组件
import { defineComponent } from 'vue'

export default defineComponent({
  setup(props, { expose }) {
    const doSomething = () => {}
    
    // 显式暴露方法
    expose({ doSomething })
    
    return { doSomething }
  }
})

// 父组件
<template>
  <ChildComponent :ref="(el) => childRef = el" />
  <button ref="btnRef"></button>
</template>

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

const childRef = ref<InstanceType<typeof ChildComponent> | null>(null)
const btnRef = ref<HTMLButtonElement | null>(null)

onMounted(() => {
  childRef.value?.doSomething()
  btnRef.value?.focus()
})
</script>
  

边界处理建议

  1. 使用可选链操作符避免未定义错误
  2. v-if控制的元素需在回调中重新获取引用
  3. 动态组件使用keep-alive时注意引用更新时机

性能优化

  • 避免高频操作DOM引发重排
  • 复杂场景优先考虑状态驱动而非DOM操作
  • 使用防抖/节流控制DOM操作频率

深度追问

  1. 为什么$refs不适合模板绑定? 由于引用非响应式,变更不会触发视图更新

  2. 如何确保动态组件的引用有效性? 使用回调函数形式::ref="(el) => dynamicRef = el"

  3. 组合式API中如何处理多个同类引用? 使用数组收集或Map结构存储动态生成的引用

Last updated 06 Mar 2025, 13:07 +0800 . history