用于性能优化的延迟加载路由
延迟加载路由是优化 Vue.js 应用程序性能的关键技术,尤其是那些具有大量路由的应用程序。通过仅在实际需要时加载路由组件,您可以显著减少应用程序的初始加载时间,从而获得更好的用户体验。这对于网络连接速度较慢或处理能力有限的设备的用户尤其重要。
了解延迟加载
延迟加载,也称为代码拆分,是一种将应用程序的代码拆分为更小的块并按需加载它们的技术。在 Vue Router 的上下文中,这意味着与特定路由关联的组件仅在用户导航到这些路由时才会加载。
为什么选择延迟加载路由?
- 减少初始加载时间: 主要优点是初始加载时间更快。浏览器不会预先下载整个应用程序,而是只下载初始视图所需的代码。
- 改进的性能: 通过减少启动时需要解析和执行的 JavaScript 数量,延迟加载可以提高应用程序的整体性能,尤其是在功能较弱的设备上。
- 更好的用户体验: 更快的加载应用程序提供更流畅、响应速度更快的用户体验,从而提高用户参与度和满意度。
- 带宽优化: 用户只需下载他们需要的代码,从而减少带宽消耗,这对于移动用户尤其重要。
Vue Router 中的延迟加载是如何工作的
Vue Router 利用 Webpack 的代码拆分功能(或其他打包器中的类似功能,如 Parcel 或 Rollup)来实现延迟加载。你不是直接导入路由的组件,而是使用返回 promise 的函数。此 promise 在需要时与组件一起 resolve。然后,Webpack 会为该组件创建一个单独的 chunk,该 chunk 在访问路由时异步加载。
在 Vue Router 中实现延迟加载
Vue Router 中惰性加载路由的核心涉及使用动态导入。让我们看看如何实现这一点。
使用动态导入
动态导入是一项 JavaScript 功能,允许您异步加载模块。在 Vue Router 中,你可以在路由配置的 component
选项中使用动态导入。
import { createRouter, createWebHistory } from 'vue-router';
const routes = [
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue') // Lazy-loaded
},
{
path: '/about',
name: 'About',
component: () => import('../views/About.vue') // Lazy-loaded
},
{
path: '/users/:id',
name: 'User',
component: () => import('../views/User.vue') // Lazy-loaded with dynamic segments
}
];
const router = createRouter({
history: createWebHistory(),
routes
});
export default router;
在此示例中,Home.vue
、About.vue
和 User.vue
组件仅在用户导航到各自的路由时加载。import()
函数返回一个 Promise,该 Promise 与组件一起解析。Webpack 会自动为这些组件创建单独的 chunk。
命名导入
如果需要从模块导入特定的命名导出,可以使用以下语法:
{
path: '/admin',
name: 'Admin',
component: () => import('../views/Admin.vue').then(module => module.AdminComponent)
}
在这里,我们从 Admin.vue
导入 AdminComponent
。当您的组件不是默认导出时,这非常有用。
将组件分组为 Chunks
Webpack 允许您将组件分组到命名的块中。这对于将相关组件逻辑分组在一起非常有用。您可以在动态导入中使用魔术注释来实现这一点:
{
path: '/dashboard',
name: 'Dashboard',
component: () => import(/* webpackChunkName: "dashboard" */ '../views/Dashboard.vue')
},
{
path: '/settings',
name: 'Settings',
component: () => import(/* webpackChunkName: "dashboard" */ '../views/Settings.vue')
}
在这种情况下,Dashboard.vue
和 Settings.vue
都将包含在一个名为 “dashboard” 的 chunk 中。如果用户经常在这两个路由之间导航,这可能是有益的,因为它避免了为每个路由下载单独的块。
处理加载和错误状态
当路由是延迟加载的时,下载组件时可能会有延迟。最好在此期间显示加载指示器。你可以使用 Vue 中的异步组件来实现这一点。
<template>
<component :is="AsyncComponent" />
</template>
<script>
import { defineAsyncComponent } from 'vue';
export default {
components: {
AsyncComponent: defineAsyncComponent({
loader: () => import('../components/MyComponent.vue'),
loadingComponent: {
template: '<div>Loading...</div>'
},
errorComponent: {
template: '<div>Failed to load component</div>'
},
delay: 200, // Display loading component after 200ms
timeout: 3000 // Abort loading after 3000ms and display the error component
})
}
};
</script>
在这里,defineAsyncComponent
允许你定义一个异步加载的组件。您可以指定在组件加载时显示 loadingComponent
,并在组件加载失败时显示 errorComponent
。delay
选项允许您避免在非常快速的加载时加载组件闪烁,而 timeout
选项允许您处理组件加载时间过长的情况。
实际示例和演示
让我们创建一个简单的 Vue 应用程序,其中包含三个路由:Home、About 和 Contact。我们将延迟加载 About 和 Contact 组件,以演示延迟加载的好处。
-
项目设置:(假设你已经安装了 Vue CLI)
vue create lazy-loading-example cd lazy-loading-example vue add router
-
创建组件:
在
src/views
目录下创建Home.vue
、About.vue
和Contact.vue
。首页 view:
<template> <h1>Home</h1> </template>
关于 vue:
<template> <h1>About</h1> </template>
联系 vue:
<template> <h1>Contact</h1> </template>
-
配置路由器:
修改
src/router/index.js
以延迟加载About
和Contact
组件。import { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') }, { path: '/contact', name: 'Contact', component: () => import(/* webpackChunkName: "contact" */ '../views/Contact.vue') } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router;
-
修改
App.vue
:向
App.vue
添加导航链接。<template> <nav> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> | <router-link to="/contact">Contact</router-link> </nav> <router-view/> </template>
-
运行应用程序:
npm run serve
打开浏览器的开发人员工具(“网络”选项卡),并在路由之间导航时观察网络请求。你会注意到
About.vue
和Contact.vue
只有在你导航到它们各自的路由时才会加载。
练习:添加加载指示器
修改上面的示例,以便在加载 About
和 Contact
组件时显示加载指示器。使用前面描述的 defineAsyncComponent
方法。
-
创建
LoadingComponent.vue
:<template> <div>Loading...</div> </template>
-
修改
src/router/index.js
:import { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; import { defineAsyncComponent } from 'vue'; import LoadingComponent from '../components/LoadingComponent.vue'; const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', component: defineAsyncComponent({ loader: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), loadingComponent: LoadingComponent, delay: 200 }) }, { path: '/contact', name: 'Contact', component: defineAsyncComponent({ loader: () => import(/* webpackChunkName: "contact" */ '../views/Contact.vue'), loadingComponent: LoadingComponent, delay: 200 }) } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router;
现在,当您导航到 About 或 Contact 路由时,您应该会看到 “Loading…”指示器。