Vue3弹窗组件首次接收Emit数据失败及赋值异常问题
Vue3弹窗组件接收Emit数据问题的解决方案
核心问题分析
- 首次点击无响应:
Welcome.vue先emitshowPopupWindow(true),紧接着emit经纬度,但此时App.vue中v-if控制的popupWindow组件还未完成挂载,mounted钩子中的事件监听器尚未注册,导致事件被直接错过。 - 二次点击赋值失败:弹窗关闭后
v-if会销毁组件,再次打开时重新挂载,若未在组件销毁时移除事件监听器,会导致重复绑定;或赋值时未正确指向组件实例的data属性。
具体修复步骤
1. 调整Emit时序,确保组件挂载后再发送数据
在Welcome.vue的emitLocation函数中,等待弹窗挂载完成后再发送经纬度数据,避免事件时序不匹配:
// Welcome.vue(选项式API) methods: { async updatePosition() { // 获取地理位置逻辑 const { latitude, longitude } = await getCurrentLocation(); this.$emit('showPopupWindow', true); // 等待弹窗完成挂载 await this.$nextTick(); this.$emit('latitude', latitude); this.$emit('longitude', longitude); } }
2. 改用props传递数据(推荐,符合Vue单向数据流)
将弹窗的显示状态和经纬度数据统一通过App.vue中转,以props形式传递给popupWindow,彻底避免事件监听的时序问题:
// App.vue <template> <div> <Welcome @trigger-popup="handleTriggerPopup" /> <popup-window v-if="showPopup" :latitude="currentLat" :longitude="currentLng" @close="showPopup = false" /> </div> </template> <script> export default { data() { return { showPopup: false, currentLat: null, currentLng: null }; }, methods: { async handleTriggerPopup() { // 也可将地理位置逻辑移至App.vue,或由Welcome.vue直接传递数据 const { latitude, longitude } = await getCurrentLocation(); this.currentLat = latitude; this.currentLng = longitude; this.showPopup = true; } } }; </script>
// Welcome.vue methods: { updatePosition() { this.$emit('trigger-popup'); } }
// popupWindow.vue export default { props: { latitude: { type: Number, required: true }, longitude: { type: Number, required: true } }, // 直接使用props中的数据,无需手动赋值 };
3. 坚持使用事件监听的修复方案
若必须使用事件监听,需在组件销毁时移除监听器,避免重复绑定,并确保监听时机正确:
// popupWindow.vue(选项式API) export default { data() { return { lat: null, lng: null }; }, mounted() { // 绑定事件监听 this.$parent.$on('latitude', (val) => { this.lat = val; }); this.$parent.$on('longitude', (val) => { this.lng = val; }); }, beforeUnmount() { // 销毁时移除监听,避免重复绑定 this.$parent.$off('latitude'); this.$parent.$off('longitude'); } };
4. 组合式API(<script setup>)的处理方式
如果使用<script setup>,可通过defineProps接收数据,或使用事件总线库(如mitt)管理事件:
// popupWindow.vue(script setup) import { defineProps, onUnmounted } from 'vue'; import mitt from 'mitt'; // 初始化事件总线 const emitter = mitt(); // 通过props接收数据(推荐) const props = defineProps({ latitude: Number, longitude: Number }); // 若使用事件总线 const handleLatUpdate = (val) => { // 赋值逻辑,如绑定到ref }; emitter.on('latitude', handleLatUpdate); // 组件销毁时移除监听 onUnmounted(() => { emitter.off('latitude', handleLatUpdate); });
内容的提问来源于stack exchange,提问作者Jakub Kosmal
相关产品推荐
相关产品推荐

