Vue组件首次加载不显示,热重载后有时显示问题求助
问题:SpecChampionData组件首次加载不显示,仅热重载后偶然出现
我有一个SpecPlayer.vue文件,其中使用了SpecChampionData组件,该组件首次加载时完全不显示,仅在热重载后(也不是每次都能成功)才会出现。我是Vue新手,日常不用TS或JS,希望能搞懂问题本质并解决。
SpecPlayer.vue代码
<script setup lang="ts"> import * as art from '@/getArt' import SpecChampionData from './SpecChampionData.vue' import { Player } from '@/types/ddata' defineProps<{ player: Player | undefined }>() </script> <template> <div class="w-full p-4 rounded-md bg-semi"> <div class="flex flex-row gap-2 flex-nowrap"> <div class="relative h-20 border-2 aspect-square avatar border-primary"> <div> <div v-if="player?.isDead" class="absolute inset-0 z-20 flex items-center justify-center aspect-square h-full text-[#ff0000]"> <h1 class="text-3xl font-bold">{{ Math.ceil(player.respawnTimer || 0) }}</h1> </div> <img v-if="player?.championName" class="avatar" :class="{ 'grayscale brightness-50': player?.isDead }" :src="art.getChampIcon(player?.championName)"> <img v-else src="/BigFist.png" class="grayscale"> <div class="absolute bottom-0 w-7 left-[50%] z-10 translate-x-[-50%] translate-y-[50%] bg-semi border-2 border-primary rounded-full aspect-square flex justify-center items-center"> <h1 class="text-sm font-medium text-center text-white">{{ player?.level || 0 }}</h1> </div> </div> </div> <div class="flex flex-col"> <h1 class="text-xl font-semibold text-primary">{{ player?.summonerName || 'Jugador' }}</h1> <h1 class="text-white">{{ player?.championName }} <h1 v-if="player?.skinName"> ({{ player?.skinName }}) </h1> </h1> </div> </div> <!-- Here is the component --> <SpecChampionData :player="player"></SpecChampionData> </div> </template>
SpecChampionData.vue代码
<template> <h1>{{ champData?.lore }}</h1> </template> <script setup lang="ts"> import axios from 'axios' import { Champion, ChampionResponse, Player } from '@/types/ddata' import { Ref, ref } from 'vue' const props = defineProps<{ player: Player | undefined }>() const champData: Ref<Champion | undefined> = ref() const champName = props.player?.championName axios.get(`https://ddragon.leagueoflegends.com/cdn/14.5.1/data/es_AR/champion/${champName}.json`) .then(res => { const resData: ChampionResponse = res.data if (champName) { champData.value = resData.data[champName] } }) </script>
问题本质分析
1. 首次加载时player可能未初始化
组件初始化时直接读取props.player?.championName,但如果父组件的player是异步获取(比如从API或其他异步逻辑加载),首次渲染时player还是undefined,此时champName为undefined,axios请求的URL会变成.../champion/undefined.json,请求失败后无法获取英雄数据,组件自然显示空内容。
热重载时,父组件的player数据可能已经加载完成,此时champName有有效值,请求能成功,所以组件能显示内容。
2. 生命周期钩子没解决的原因
你之前尝试的onBeforeMount/onMounted只在组件初始化时执行一次,如果执行时player仍为undefined,后续player更新时不会重新触发请求,问题依然存在。
解决方案
1. 监听player变化,自动触发请求
修改SpecChampionData.vue,使用watch监听player.championName的变化,每当英雄名称更新或首次初始化时,自动发起请求:
<template> <h1>{{ champData?.lore || '暂无英雄背景故事' }}</h1> </template> <script setup lang="ts"> import axios from 'axios' import { Champion, ChampionResponse, Player } from '@/types/ddata' import { Ref, ref, watch } from 'vue' const props = defineProps<{ player: Player | undefined }>() const champData: Ref<Champion | undefined> = ref() // 封装请求逻辑,方便复用 const fetchChampionData = () => { const champName = props.player?.championName if (!champName) { champData.value = undefined return } // 发起请求获取英雄数据 axios.get(`https://ddragon.leagueoflegends.com/cdn/14.5.1/data/es_AR/champion/${champName}.json`) .then(res => { const resData: ChampionResponse = res.data champData.value = resData.data[champName] }) .catch(err => { console.error('获取英雄数据失败:', err) // 打印错误方便排查 }) } // 监听英雄名称变化,自动执行请求 watch( () => props.player?.championName, // 只监听英雄名称字段 () => fetchChampionData(), { immediate: true } // 组件初始化时立即执行一次 ) </script>
2. 增加加载状态(可选优化)
如果请求需要一定时间,可添加加载提示提升用户体验:
<template> <div v-if="isLoading" class="text-white">加载中...</div> <h1 v-else>{{ champData?.lore || '暂无英雄背景故事' }}</h1> </template> <script setup lang="ts"> // 保留上面的代码,新增加载状态变量 const isLoading = ref(false) const fetchChampionData = () => { const champName = props.player?.championName if (!champName) { champData.value = undefined isLoading.value = false return } isLoading.value = true // 开始加载 axios.get(...) .then(res => { // 处理数据逻辑 isLoading.value = false // 加载完成 }) .catch(err => { console.error(err) isLoading.value = false // 加载失败也关闭加载状态 }) } </script>
3. 父组件条件渲染(可选优化)
在SpecPlayer.vue中,只有当player存在时再渲染SpecChampionData,避免无效请求:
<!-- 替换原有的SpecChampionData标签 --> <SpecChampionData v-if="player" :player="player"></SpecChampionData>
内容的提问来源于stack exchange,提问作者p1etrito
相关产品推荐
相关产品推荐

