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

Nuxt3组件首次渲染加载器设置及Element Plus标签切换卡顿解决

解决方案:Nuxt3 + Element Plus 标签页组件首次切换延迟与加载器实现

问题原因

你遇到的首次切换延迟,本质是Lazy组件的按需加载机制导致的:Nuxt的LazyComponent语法糖会把组件打包成独立的chunk文件,只有当组件被首次渲染(v-if条件满足)时,才会发起网络请求加载对应的chunk资源,这中间的网络请求和解析时间就是你感知到的延迟。

解决延迟的两种核心方案

1. 提前预加载组件

通过主动触发组件chunk的加载,避免用户点击时的等待。

方案A:页面挂载后后台预加载

在页面挂载完成后,异步加载另外两个组件的chunk,这样用户切换时资源已经加载完毕:

<script setup>
const activeTabName = ref("tab1");
// 标记组件是否已加载
const loadedTabs = reactive({
  tab1: true,
  tab2: false,
  tab3: false
});

// 预加载组件函数
const preloadTabComponent = async (tabName) => {
  if (!loadedTabs[tabName]) {
    // 路径根据你的组件实际位置调整
    switch(tabName) {
      case 'tab2':
        await import('~/components/Tab2.vue');
        break;
      case 'tab3':
        await import('~/components/Tab3.vue');
        break;
    }
    loadedTabs[tabName] = true;
  }
};

onMounted(async () => {
  await getDetails();
  // 后台预加载tab2和tab3的组件,不阻塞页面渲染
  Promise.all([preloadTabComponent('tab2'), preloadTabComponent('tab3')]);
});
</script>

方案B:标签hover时预加载

在用户鼠标悬停到非激活标签时触发预加载,更贴近用户操作场景:

<template>
<el-tabs v-model="activeTabName">
  <el-tab-pane label="Tab 1" name="tab1">
    <!-- ... -->
  </el-tab-pane>
  <el-tab-pane label="Tab 2" name="tab2" @mouseenter="preloadTabComponent('tab2')">
    <!-- ... -->
  </el-tab-pane>
  <el-tab-pane label="Tab 3" name="tab3" @mouseenter="preloadTabComponent('tab3')">
    <!-- ... -->
  </el-tab-pane>
</el-tabs>
</template>

2. 优化组件体积

如果组件本身体积过大,也会导致加载延迟,可通过以下方式优化:

  • 拆分组件内的大模块(比如复杂的表单校验逻辑、大型图表)为更小的子组件
  • 移除组件内未使用的Element Plus组件(Nuxt3会自动树摇,但手动清理更彻底)
  • 对组件内的静态资源(如图片)进行压缩

实现组件首次渲染加载器

通过跟踪组件的加载状态,在组件未加载完成时显示加载动画,提升用户体验:

修改后的完整代码

<template>
<el-tabs v-model="activeTabName">
  <el-tab-pane label="Tab 1" name="tab1">
    <LazyTab1
      v-if="activeTabName == 'tab1'"
      :form-data="formData"
      :loader="loader"
      @on-submit="submitForm"
    />
  </el-tab-pane>
  <el-tab-pane label="Tab 2" name="tab2" @mouseenter="preloadTabComponent('tab2')">
    <!-- 加载状态显示 -->
    <div v-if="activeTabName == 'tab2' && !loadedTabs.tab2" class="tab-loader">
      <el-spinner size="40" />
      <p>加载中...</p>
    </div>
    <LazyTab2
      v-else-if="activeTabName == 'tab2'"
      :form-data="formData"
      :loader="loader"
      @submit-form="submitForm"
      @loaded="loadedTabs.tab2 = true"
    />
  </el-tab-pane>
  <el-tab-pane label="Tab 3" name="tab3" @mouseenter="preloadTabComponent('tab3')">
    <div v-if="activeTabName == 'tab3' && !loadedTabs.tab3" class="tab-loader">
      <el-spinner size="40" />
      <p>加载中...</p>
    </div>
    <LazyTab3
      v-else-if="activeTabName == 'tab3'"
      :form-data="formData"
      :loader="loader"
      @on-submit="submitForm"
      @loaded="loadedTabs.tab3 = true"
    />
  </el-tab-pane>
</el-tabs>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
const activeTabName = ref("tab1");
const loadedTabs = reactive({
  tab1: true,
  tab2: false,
  tab3: false
});
// 修正原代码笔误:重复的tab2改为tab3
const formData = reactive({
  tab1: {
    // ...
  },
  tab2: {
    // ...
  },
  tab3: {
    // ...
  }
});

const preloadTabComponent = async (tabName) => {
  if (!loadedTabs[tabName]) {
    try {
      // 路径根据你的组件实际位置调整
      switch(tabName) {
        case 'tab2':
          await import('~/components/Tab2.vue');
          break;
        case 'tab3':
          await import('~/components/Tab3.vue');
          break;
      }
      loadedTabs[tabName] = true;
    } catch (e) {
      console.error(`预加载${tabName}组件失败`, e);
    }
  }
};

const submitForm = async (formRef) => {
  // ...提交逻辑
};

const getDetails = async () => {
  // ...API请求逻辑
};

onMounted(async () => {
  await getDetails();
  // 可选:后台预加载,可根据业务需求决定是否开启
  // Promise.all([preloadTabComponent('tab2'), preloadTabComponent('tab3')]);
});
</script>

<style scoped>
.tab-loader {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 300px;
  gap: 12px;
}
</style>

补充说明

  • 子组件需添加loaded事件:在Tab2、Tab3组件的onMounted钩子中执行$emit('loaded'),告知父组件已加载完成。
  • 也可以用Element Plus的v-loading指令替代自定义加载器,直接给tab-pane的容器添加v-loading="!loadedTabs.tab2"。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:08:12