You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3 Composition API 父组件访问子组件ref的实现方法

问题原因

<script setup> 语法默认存在作用域闭包,组件内部声明的ref、变量等成员不会自动对外暴露,父组件无法直接访问子组件内部的mainContentRef。另外你代码中mainContentRef初始值设为0是错误写法,DOM类型的ref初始值应当设为null。

方案1:通过defineExpose暴露子组件内部ref

如果确实需要在父组件中直接拿到滚动容器DOM,可以通过Vue提供的defineExpose宏手动暴露子组件内部成员,步骤如下:

  • 修改子组件代码,修正ref初始值,添加暴露逻辑:
<!-- MainContent 子组件 -->
<template>
  <div id="main-content" ref="mainContentRef">
    <slot name="content"></slot>
  </div>
</template>

<script setup>
import { ref } from 'vue';
// DOM引用初始值设为null
const mainContentRef = ref(null);
// 手动暴露指定成员给父组件
defineExpose({
  mainContentRef
})
</script>
  • 父组件中给子组件标签绑定ref,在组件挂载完成后即可拿到DOM实例,绑定滚动事件:
<!-- 父组件 -->
<template>
  <PageWrap>
    <template v-slot:content>
      <!-- 给子组件标签绑定ref,用于获取子组件实例 -->
      <MainContent ref="mainContentCompRef">
        <template v-slot:content />
      </MainContent>
    </template>
  </PageWrap>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
// 子组件实例引用
const mainContentCompRef = ref(null);

const handleScroll = (e) => {
  const scrollContainer = e.target;
  // 滚动到底部判定逻辑,阈值可根据业务调整
  if (scrollContainer.scrollTop + scrollContainer.clientHeight >= scrollContainer.scrollHeight - 20) {
    // 执行fetch拉取更多数据
  }
}

onMounted(() => {
  // 从子组件实例上拿到暴露的DOM,绑定滚动事件
  const scrollEl = mainContentCompRef.value.mainContentRef;
  scrollEl?.addEventListener('scroll', handleScroll);
})

// 组件卸载前移除事件监听,避免内存泄漏
onBeforeUnmount(() => {
  const scrollEl = mainContentCompRef.value?.mainContentRef;
  scrollEl?.removeEventListener('scroll', handleScroll);
})
</script>
方案2:子组件派发自定义事件(更推荐)

如果只是需要在滚动触底时触发父组件的拉取逻辑,完全没必要跨组件传递DOM引用,这种方案耦合度更低:子组件自己维护内部DOM的事件监听,滚动到指定位置时对外抛出业务语义的事件,父组件只需要监听对应事件执行业务逻辑即可,不需要关心子组件的内部DOM结构,后续子组件调整滚动容器时父组件代码无需修改。

  • 子组件代码:
<!-- MainContent 子组件 -->
<template>
  <div id="main-content" ref="mainContentRef">
    <slot name="content"></slot>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
const emit = defineEmits(['scroll-reach-bottom']);
const mainContentRef = ref(null);

const handleContainerScroll = (e) => {
  const scrollContainer = e.target;
  if (scrollContainer.scrollTop + scrollContainer.clientHeight >= scrollContainer.scrollHeight - 20) {
    emit('scroll-reach-bottom');
  }
}

onMounted(() => {
  mainContentRef.value?.addEventListener('scroll', handleContainerScroll);
})

onBeforeUnmount(() => {
  mainContentRef.value?.removeEventListener('scroll', handleContainerScroll);
})
</script>
  • 父组件代码:
<!-- 父组件 -->
<template>
  <PageWrap>
    <template v-slot:content>
      <!-- 直接监听子组件抛出的业务事件 -->
      <MainContent @scroll-reach-bottom="fetchMoreList">
        <template v-slot:content />
      </MainContent>
    </template>
  </PageWrap>
</template>

<script setup>
const fetchMoreList = () => {
  // 执行拉取更多数据的请求逻辑
}
</script>

内容的提问来源于stack exchange,提问作者Bryan88

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:33:39