面试题:如何访问 Vue 子组件的实例或子元素?

在 Vue 中,有时需要从父组件直接访问子组件的实例或其内部的 DOM 元素。Vue 提供了 ref 特性来实现这一需求。

核心方法:使用 ref

  1. 在子组件或元素上定义 ref
    在父组件的模板中,为要访问的子组件或原生元素添加 ref 属性,并为其指定一个唯一的名称。
  2. 通过 $refs 访问
    在父组件的实例中,可以通过 this.$refs.名称 来访问对应的子组件实例或 DOM 元素。

详细示例

场景一:访问子组件实例

<!-- 子组件 ChildComponent.vue -->
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
  data() {
    return {
      message: 'Hello from child!'
    }
  },
  methods: {
    // 定义一个可以被父组件调用的方法
    updateMessage(newMsg) {
      this.message = newMsg;
    }
  }
}
</script>
<!-- 父组件 ParentComponent.vue -->
<template>
  <div>
    <!-- 为子组件绑定 ref -->
    <ChildComponent ref="childComp" />
    <button @click="callChildMethod">调用子组件方法</button>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue'

export default {
  components: {
    ChildComponent
  },
  methods: {
    callChildMethod() {
      // 通过 $refs 访问子组件实例并调用其方法
      this.$refs.childComp.updateMessage('Message updated by parent!');

      // 也可以直接修改子组件的数据(不推荐,破坏封装)
      // this.$refs.childComp.message = 'Directly changed';
    }
  }
}
</script>

场景二:访问子元素(DOM 元素)

<!-- 父组件 -->
<template>
  <div>
    <!-- 为原生 HTML 元素绑定 ref -->
    <input ref="inputRef" type="text" placeholder="Focus me!" />
    <button @click="focusInput">聚焦输入框</button>
  </div>
</template>

<script>
export default {
  methods: {
    focusInput() {
      // 通过 $refs 访问 DOM 元素并调用其方法
      this.$refs.inputRef.focus();
    }
  }
}
</script>

重要注意事项

  1. $refs 只在组件渲染完成后才填充
    • $refs 不是响应式的。
    • 它只会在组件挂载 (mounted) 之后才可用。
    • 如果你在 created 钩子中尝试访问 this.$refs,它会是 undefined
  2. 避免过度使用
    • 直接访问子组件实例通常被认为是“打破封装”的做法。
    • 优先使用 propsevents 进行父子通信。这是 Vue 推荐的、更清晰和可维护的方式。
    • 只有在确实需要调用子组件的方法或直接操作 DOM(如聚焦、滚动)时才使用 ref
  3. ref 的值取决于绑定的目标
    • 绑定到组件上:$refs.xxx子组件的实例,可以访问其 datamethodscomputed 等。
    • 绑定到原生 HTML 元素上:$refs.xxx原生的 DOM 元素,可以直接调用 DOM API。
  4. v-for 中的 ref
    • ref 用在 v-for 内部的元素或组件上时,$refs.xxx 将会是一个包含相应 DOM 节点或组件实例的数组
  5. Composition API (Vue 3)
    • <script setup> 中,需要使用 ref() 函数创建一个响应式引用,并通过 defineExpose 显式暴露需要被父组件访问的属性或方法。

总结

通过在模板中使用 ref="name" 并在父组件中通过 this.$refs.name 访问,可以获取子组件实例或子元素的 DOM 节点。虽然这是一个强大的功能,但应谨慎使用,优先考虑通过 props 传递数据和通过自定义事件 ($emit) 进行通信的正向数据流模式。

THE END
喜欢就支持一下吧
点赞10 分享