如何为Nuxt 3中的懒加载组件设置自定义加载器?
解决方案
问题根源
- Reactive对象赋值错误:直接给
reactive声明的formData/formData2赋值会丢失响应性——reactive返回的是代理对象,不能直接替换引用。 - 加载状态未关联数据请求:Nuxt的
Lazy组件默认加载状态是组件代码本身的加载状态,而非数据请求状态。首次切换标签时,组件完成懒加载后立即渲染,但对应的数据还未加载完成,导致加载器不显示;再次切换时数据已缓存,所以显示正常。 - 数据请求时机不合理:一次性在
onMounted请求所有数据,可能导致非激活标签的数据加载延迟,无法匹配标签切换的加载状态。
修复步骤
1. 修正响应式数据赋值
用Object.assign更新reactive对象,保留响应性:
if (data.value) { Object.assign(formData, data.value.data1); Object.assign(formData2, data.value.data2); Object.assign(formData3, data.value.data3); }
2. 为每个标签添加独立加载状态
给每个tab的数据请求设置专属加载状态变量,精准控制加载器显示:
const activeTabName = ref("tab1"); const formData = reactive({}); const formData2 = reactive({}); const formData3 = reactive({}); // 每个tab的加载状态 const loadingStates = reactive({ tab1: false, tab2: false, tab3: false });
3. 按需请求数据(切换标签时触发)
改为切换标签时才请求对应数据,让加载状态完全匹配标签切换行为:
// 封装数据请求函数 const fetchTabData = async (tabName) => { loadingStates[tabName] = true; try { const { data, error } = await useFetch(`api-url/${tabName}`); // 根据tab调整接口路径 if (data.value) { if (tabName === 'tab1') Object.assign(formData, data.value); if (tabName === 'tab2') Object.assign(formData2, data.value); if (tabName === 'tab3') Object.assign(formData3, data.value); } if (error.value) console.log(error.value); } finally { loadingStates[tabName] = false; } }; // 初始加载第一个tab的数据 onMounted(() => { fetchTabData('tab1'); }); // 监听标签切换,加载对应未缓存的数据 watch(activeTabName, (newTab) => { const targetData = newTab === 'tab1' ? formData : newTab === 'tab2' ? formData2 : formData3; if (Object.keys(targetData).length === 0) { fetchTabData(newTab); } });
4. 自定义Lazy组件加载器(关联数据加载状态)
使用Nuxt Lazy组件的#fallback插槽自定义加载器,结合对应tab的加载状态控制显示:
<template> <el-tabs v-model="activeTabName"> <el-tab-pane label="Tab 1" name="tab1"> <LazyMyComponent :data="formData"> <template #fallback> <div v-if="loadingStates.tab1" class="custom-loader"> <el-loading-spinner /> <p>加载中...</p> </div> </template> </LazyMyComponent> </el-tab-pane> <el-tab-pane label="Tab 2" name="tab2"> <LazyMyComponent :data="formData2"> <template #fallback> <div v-if="loadingStates.tab2" class="custom-loader"> <el-loading-spinner /> <p>加载中...</p> </div> </template> </LazyMyComponent> </el-tab-pane> <el-tab-pane label="Tab 3" name="tab3"> <LazyMyComponent :data="formData3"> <template #fallback> <div v-if="loadingStates.tab3" class="custom-loader"> <el-loading-spinner /> <p>加载中...</p> </div> </template> </LazyMyComponent> </el-tab-pane> </el-tabs> </template>
5. 可选:组件内部处理加载状态
如果MyComponent支持内部判断,可直接在组件内根据传入的data是否为空显示加载状态:
<!-- MyComponent.vue --> <template> <div v-if="Object.keys(data).length === 0" class="custom-loader"> <el-loading-spinner /> <p>加载中...</p> </div> <div v-else> <!-- 组件业务内容 --> </div> </template> <script setup> const props = defineProps({ data: { type: Object, default: () => ({}) } }); </script>
修改后,首次切换标签时会触发对应数据请求,加载状态变量会精准控制加载器显示,直到数据加载完成后隐藏,解决首次切换加载器不生效的问题。
内容的提问来源于stack exchange,提问作者Kishan Bhensadadiya
相关产品推荐
相关产品推荐

