vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue父组件监听子组件

Vue中父组件监听子组件挂载完成的操作过程

作者:藤原とラふ店丶

文章介绍了父组件监听子组件挂载完成的可靠方法,通过子组件主动发送事件通知父组件,实现父子组件之间的通信,文章结合实例代码介绍了Vue中父组件监听子组件挂载完成的实例代码,感兴趣的朋友跟随小编一起看看吧

父组件监听子组件挂载完成,核心逻辑是 子组件在自身挂载完毕后主动向父组件发送事件,父组件监听该事件并执行后续操作(比如调用子组件方法)。这种方式最可靠,能确保子组件完全渲染+初始化完成,适配 Vue2、Vue3 所有版本,下面分场景详细说明实现步骤和注意事项:

一、核心原理

  1. 子组件生命周期:mounted 钩子触发时,子组件已完成 DOM 渲染、自身初始化(无异步逻辑时),是“挂载完成”的关键节点;
  2. 父子通信:子组件通过 $emit(Vue2/Vue3 选项式)或 defineEmits(Vue3 组合式)发送自定义事件(比如 mounted-complete);
  3. 父组件响应:在模板中通过 @事件名 监听子组件事件,回调函数中即可安全操作子组件(调用方法、访问属性)。

二、分版本实现(含完整代码)

场景 1:Vue2(选项式 API)

1. 子组件:挂载完成后发送事件

<!-- 子组件 Child.vue(Vue2) -->
<template>
  <div>子组件内容</div>
</template>
<script>
export default {
  name: 'ChildComponent',
  mounted() {
    // 关键:子组件挂载完毕,向父组件发送事件(事件名建议 kebab-case)
    this.$emit('mounted-complete'); 
  },
  methods: {
    // 父组件要调用的子组件方法
    childMethod() {
      console.log('子组件方法执行(已挂载完成)');
    }
  }
}
</script>

2. 父组件:监听事件并调用方法

<!-- 父组件 Parent.vue(Vue2) -->
<template>
  <!-- 1. v-if 控制子组件显示;2. ref 绑定子组件;3. @监听子组件事件 -->
  <ChildComponent
    v-if="isChildShow"
    ref="childRef"
    @mounted-complete="handleChildMounted" <!-- 监听挂载完成事件 -->
  />
  <button @click="showChild">显示子组件</button>
</template>
<script>
import ChildComponent from './Child.vue';
export default {
  components: { ChildComponent },
  data() {
    return { isChildShow: false };
  },
  methods: {
    // 触发子组件显示
    showChild() {
      this.isChildShow = true;
    },
    // 子组件挂载完成后的回调(核心)
    handleChildMounted() {
      // 此时子组件已完全挂载,$refs 一定存在,可安全调用方法
      this.$refs.childRef.childMethod();
      // (可选)访问子组件属性
      console.log('子组件属性:', this.$refs.childRef.childProp);
    }
  }
}
</script>

场景 2:Vue3(选项式 API,与 Vue2 兼容)

逻辑和 Vue2 一致,仅语法细微差异(无需 name 也可正常通信):

<!-- 子组件 Child.vue(Vue3 选项式) -->
<script>
export default {
  mounted() {
    this.$emit('mounted-complete'); // 同样用 $emit 发事件
  },
  methods: {
    childMethod() { /* ... */ }
  }
}
</script>
<!-- 父组件 Parent.vue(Vue3 选项式) -->
<template>
  <ChildComponent v-if="isChildShow" ref="childRef" @mounted-complete="handleChildMounted" />
</template>
<script>
import ChildComponent from './Child.vue';
export default {
  components: { ChildComponent },
  data() { return { isChildShow: false }; },
  methods: {
    showChild() { this.isChildShow = true; },
    handleChildMounted() { this.$refs.childRef.childMethod(); }
  }
}
</script>

场景 3:Vue3(组合式 API / setup 语法,推荐)

Vue3 组合式 API 需用 defineEmits 声明事件,ref 绑定方式略有不同:

1. 子组件:用 defineEmits 声明事件并发送

<!-- 子组件 Child.vue(Vue3 setup) -->
<template>
  <div>子组件内容</div>
</template>
<script setup>
// 1. 声明要发送的事件(TypeScript 可选,增强类型提示)
const emit = defineEmits(['mounted-complete']);
// 2. 模拟子组件挂载完成(mounted 钩子等价于 setup 中直接执行异步逻辑后触发)
// 注:setup 执行时机是 beforeCreate -> created 之间,需用 onMounted 监听挂载
import { onMounted } from 'vue';
onMounted(() => {
  // 挂载完成后发送事件
  emit('mounted-complete'); 
});
// 子组件方法(需用 defineExpose 暴露给父组件)
const childMethod = () => {
  console.log('Vue3 子组件方法执行(已挂载)');
};
// 关键:setup 中定义的方法/属性,需显式暴露才能被父组件 $refs 访问
defineExpose({ childMethod });
</script>

2. 父组件:监听事件并调用暴露的方法

<!-- 父组件 Parent.vue(Vue3 setup) -->
<template>
  <ChildComponent
    v-if="isChildShow"
    ref="childRef" <!-- 用 ref 绑定子组件实例 -->
    @mounted-complete="handleChildMounted" <!-- 监听事件 -->
  />
  <button @click="isChildShow = true">显示子组件</button>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './Child.vue';
// 1. 控制子组件显示的开关
const isChildShow = ref(false);
// 2. 绑定子组件的 ref(初始为 null)
const childRef = ref(null);
// 3. 子组件挂载完成后的回调
const handleChildMounted = () => {
  // 此时 childRef.value 是子组件实例,且已暴露 childMethod
  childRef.value.childMethod(); // 安全调用
};
</script>

三、进阶场景:子组件有异步初始化逻辑

如果子组件 mounted 中存在异步操作(比如请求接口、加载资源),仅靠 mounted 只能保证 DOM 渲染,不能保证异步逻辑完成。此时需修改子组件:在异步逻辑结束后再发送事件

示例(子组件有接口请求):

<!-- 子组件 Child.vue(Vue3 setup) -->
<script setup>
const emit = defineEmits(['mounted-complete']);
import { onMounted } from 'vue';
// 子组件方法(依赖接口返回数据)
const childMethod = (data) => {
  console.log('子组件方法执行,数据:', data);
};
onMounted(async () => {
  // 模拟异步接口请求(实际开发中是 axios/fetch)
  const res = await fetch('/api/child-data');
  const data = await res.json();
  // 异步逻辑完成后,再发送“挂载+初始化完成”事件(可携带数据)
  emit('mounted-complete', data); 
});
defineExpose({ childMethod });
</script>
<!-- 父组件 Parent.vue(Vue3 setup) -->
<script setup>
// ... 其他代码不变
const handleChildMounted = (data) => {
  // 接收子组件传递的异步数据,再调用方法
  childRef.value.childMethod(data);
};
</script>

四、关键注意事项(避免踩坑)

  1. 事件命名规范:推荐用 kebab-case(短横线分隔),比如 mounted-complete,避免驼峰(Vue 模板中不区分大小写,可能导致事件监听失效);
  2. Vue3 setup 必须暴露方法:setup 中定义的方法/属性默认是“私有”的,需用 defineExpose 显式暴露,父组件才能通过 ref 访问;
  3. 避免重复触发:如果子组件可能多次挂载(比如 v-if 反复切换 true/false),父组件回调会多次执行,可通过标志位控制:
// 父组件中添加标志位
const isChildMounted = ref(false);
const handleChildMounted = () => {
  if (!isChildMounted.value) {
    childRef.value.childMethod();
    isChildMounted.value = true; // 执行一次后标记
  }
};
  1. 兜底判断:极端情况下(比如子组件内部有条件渲染导致未真正挂载),可加可选链判断:
// Vue2:this.$refs.childRef?.childMethod();(需开启 ES6+ 可选链语法)
// Vue3:childRef.value?.childMethod();(天然支持)

五、总结

父组件监听子组件挂载完成的核心流程:

  1. 子组件:在「挂载完成 + 初始化完成」时,通过 $emit/defineEmits 发送事件;
  2. 父组件:监听该事件,在回调中通过 $refs 安全操作子组件;
  3. 适配场景:
    • 简单场景(无异步):子组件 mounted 中发事件;
    • 复杂场景(有异步):子组件异步逻辑结束后发事件;
    • Vue2 用 $emit,Vue3 setup 用 defineEmits + defineExpose

这种方式比 $nextTick 更可靠,因为它是子组件“主动通知”,能确保子组件完全就绪,不会出现 undefined 报错。

到此这篇关于Vue中父组件监听子组件挂载完成的操作过程的文章就介绍到这了,更多相关vue父组件监听子组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文