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

Vue3 Suspense懒加载路由组件后Loading不消失解决方法

问题描述

在实现Login路由组件懒加载时,使用<Suspense>组件搭配default、fallback插槽实现加载状态提示,加载触发逻辑正常,但存在异常:目标异步组件加载完成后,Loading状态的内容始终不会卸载消失。

相关代码

router.js 配置代码

import { createWebHistory, createRouter } from 'vue-router'


const Login = () => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(
                import ('./components/pages/auth/Login'),
            )
        }, 1000)
    })
}
const Register = () => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(
                import ('./components/pages/auth/Register'),
            )
        }, 1000)
    })
}

const routes = [{
        path: '/login',
        name: 'login',
        component: Login,
    },
    {
        path: '/register',
        name: 'register',
        component: Register,
    }
]

const router = createRouter({
    history: createWebHistory(),
    routes: routes
})

export default router

根组件App.vue代码

<template>
    <div>
        <Suspense>
            <template #default>
                <RouterView />
            </template>
            <template #fallback>
                <div>
                    <h1>Loading....</h1>
                </div>
            </template>
        </Suspense>
    </div>
</template>
<script>
export default {
    components: {

    }
}
</script>
<style scoped>
div {
    height: 100%;
    width: 100%;
    background-color: black;
}

h1 {
    font-size: 30px;
    font-weight: bold;
    color: white;
}
</style>

异常表现

组件加载完成后,加载态的黑色背景仍然残留,不符合预期。

问题原因

问题由三个核心问题共同导致:

  • Suspense无法感知路由组件加载状态:直接将<RouterView />作为Suspense默认插槽内容时,<RouterView>本身是同步组件,其内部渲染异步路由组件的加载状态不会冒泡给外层Suspense,导致Suspense始终判定默认插槽内容处于未就绪状态,因此一直保留fallback插槽的Loading内容。
  • 不规范的异步组件写法:手动为import()动态导入包裹自定义Promise的写法不符合Vue 3异步组件规范,会导致Suspense无法正确识别组件加载完成的时机。
  • 样式污染放大异常表现:App.vue的scoped样式中直接对div标签设置了全屏黑色背景样式,该样式会命中组件作用域下所有div元素,哪怕后续业务组件渲染完成,外层容器div也会被加上黑色背景,进一步造成Loading完全没卸载的视觉错觉。
修复方案

按以下步骤调整代码即可解决问题:

  • 调整RouterView写法,使用RouterView的作用域插槽拿到当前渲染的路由组件,直接将动态组件渲染在插槽内,保证异步组件的状态可以冒泡到外层Suspense。
  • 使用官方defineAsyncComponentAPI定义懒加载路由组件,开启suspensible: true配置支持Suspense接管加载状态,不要手动裸写Promise包裹动态导入。
  • 给Loading容器添加专属类名,避免无差别标签选择器污染其他元素样式。

修复后的参考代码

router.js 修正后代码

import { createWebHistory, createRouter } from 'vue-router'
import { defineAsyncComponent } from 'vue'

// 用官方API定义支持Suspense的异步组件,模拟1s加载延迟
const Login = defineAsyncComponent({
  suspensible: true,
  loader: () => new Promise((resolve) => {
    setTimeout(() => {
      resolve(import('./components/pages/auth/Login.vue'))
    }, 1000)
  })
})
const Register = defineAsyncComponent({
  suspensible: true,
  loader: () => new Promise((resolve) => {
    setTimeout(() => {
      resolve(import('./components/pages/auth/Register.vue'))
    }, 1000)
  })
})

const routes = [
  {
    path: '/login',
    name: 'login',
    component: Login,
  },
  {
    path: '/register',
    name: 'register',
    component: Register,
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes: routes
})

export default router

App.vue 修正后代码

<template>
    <div class="app-container">
        <Suspense>
            <template #default>
                <!-- 使用作用域插槽透传路由组件,让Suspense感知异步加载状态 -->
                <RouterView v-slot="{ Component }">
                  <component :is="Component" />
                </RouterView>
            </template>
            <template #fallback>
                <!-- 给Loading容器加专属类名避免样式污染 -->
                <div class="loading-wrap">
                    <h1>Loading....</h1>
                </div>
            </template>
        </Suspense>
    </div>
</template>
<script>
export default {}
</script>
<style scoped>
.app-container {
  height: 100%;
  width: 100%;
}
.loading-wrap {
    height: 100%;
    width: 100%;
    background-color: black;
}

h1 {
    font-size: 30px;
    font-weight: bold;
    color: white;
}
</style>

注:如果不需要手动模拟加载延迟,路由组件可以直接简写为() => import('./xxx/xxx.vue'),Vue Router和Vue会自动处理异步组件的Suspense适配,无需额外包裹defineAsyncComponent。


内容的提问来源于stack exchange,提问作者Joseph Onipede

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:09:29