在项目涉及到用户体验和性能优化,不得不提异步组件和异步页面。这对于创建高性能、响应式且用户友好的应用程序至关重要。通过延迟加载、代码拆分和按需加载,它们可以提高性能、优化用户体验并提高代码的可维护性。 最终示例效果如下
异步页面或异步组件优化作用和意义以下几个方面:
- 提高性能:通过延迟加载或分块加载代码,异步组件和异步页面可以显著提高应用程序的性能。这对于大型和复杂的应用程序尤为重要,因为它们通常需要加载大量代码。通过异步加载,可以减少初始加载时间,从而为用户提供更好的体验。
- 优化用户体验:异步加载还可以优化用户体验。当页面或组件延迟加载时,用户可以立即看到加载指示符或占位符,从而让他们知道正在加载内容。这比长时间等待所有内容加载要好得多,因为用户可以继续与应用程序交互,而不用等待。
- 代码拆分:异步组件和异步页面促进代码拆分,这有助于提高可维护性和可扩展性。通过将代码拆分成较小的模块,可以更容易地管理和更新代码,特别是对于大型应用程序。此外,代码拆分可以减少捆绑文件的大小,从而加快加载时间。
- 按需加载:异步组件和异步页面允许按需加载内容。这意味着只有在需要时才会加载特定组件或页面。这可以节省带宽并减少内存使用,特别是在处理大量数据或具有复杂导航的应用程序时。
- 渐进式显示:异步页面还可以实现渐进式显示。这允许页面内容随着加载的进行逐渐显示,为用户提供更好的体验。例如,一个异步页面可以先显示标题和侧边栏,然后随着内容的加载逐渐显示正文和图像。
通过vite创建vue3项目
npm create vite@latest
Ok to proceed? (y) y
√ Project name: ... vite-vue3-app
√ Select a framework: » Vue
√ Select a variant: » JavaScript
创建完成后进入该项目下,初始化项目并运行
cd vite-vue3-app
npm install
npm run dev
创建tabbar
由于我这边demo是移动端模板,需要导入一个移动端ui库(主要用切换页面和骨架屏ui,这个看各位熟悉度,antd、elementui都可以)
以我当前项目为例子,vntd4框架vant-ui.github.io/vant/#/zh-C…
# Vue 3 项目,安装最新版 Vant
npm i vant
# Vue 2 项目,安装 Vant 2
npm i vant@latest-v2
# 通过 yarn 安装
yarn add vant
安装完成进入main.js完成组件的导入,完整的文件如下
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
//导入Tabbar
import { Tabbar, TabbarItem } from 'vant';
//引入vant组件样式
import 'vant/lib/index.css';
//导入路由,后面会讲
import router from './router'
//导入骨架屏
import {
Skeleton,
SkeletonTitle,
SkeletonImage,
SkeletonAvatar,
SkeletonParagraph,
} from 'vant';
//添加插件
createApp(App)
.use(router)
.use(Tabbar)
.use(TabbarItem)
.use(Skeleton)
.use(SkeletonTitle)
.use(SkeletonImage)
.use(SkeletonAvatar)
.use(SkeletonParagraph)
.mount('#app')
然后修改App.vue页面,完整代码如下:
<script setup>
import HelloWorldVue from "./components/HelloWorld.vue";
import { ref } from "vue";
const active = ref(0);
</script>
<template>
<div>
<router-view />
<van-tabbar v-model="active">
<van-tabbar-item icon="home-o" > <router-link to="/">主页</router-link></van-tabbar-item>
<van-tabbar-item icon="setting" ><router-link to="/Setting">设置</router-link></van-tabbar-item>
</van-tabbar>
</div>
</template>
<style scoped>
#app {
margin: 0 auto !important;
padding: 0 !important;
text-align: center;
}
</style>
然后完成下面tabber功能
创建页面
在src文件夹下创建两个文件Home.vue、Setting.vue
Setting.vue页面上填写下面内容,Home.vue页面先暂时和Setting.vue页面保持一致
<template>
<div>切换页面测试</div>
</template>
安装路由
运行下面代码
npm install vue-router
配置路由,在src文件夹下创建两个文件index.js、routes.js
index.js文件内容如下
import { createRouter,createWebHistory } from "vue-router";
import routes from "./routes"
export default createRouter({
history:createWebHistory(),//路由方式history
routes
})
routes.js文件内容如下
import { getAsyncPage } from "../utils/index.js"
const Home = getAsyncPage("../views/Home.vue");
const Setting = getAsyncPage("../views/Setting.vue");
export default [
{path:"/",component:Home},
{path:"/Setting",component:Setting},
]
记得在main.js导入插件
路由安装完成,此时运行代码,可以看到页面如下,并且可以切换页面
完善其他页面
先看下页面结构,其他页面主要包含三个,错误页,骨架屏页,页面切换加载中页面,下面将展示完整的代码。
Error.vue页面,简单展示错误消息,并且错误消息通过插槽slot传入。
<template>
<div style="color: red;font-size: 18px;" >
<slot></slot>
</div>
</template>
Skeleton.vue页面,展示加载中效果,并且该页面占满整个父级组件
注意:这里是举例子:可以根据实际业务需求进行调整,例如放图片,或者svg动画。
<template>
<div class="temp" style="">
<van-skeleton title :row="1" />
</div>
</template>
<style scoped>
.temp{
width: 100%;
height: 100%;
margin: auto 0;
padding: 20px 0;
}
</style>
Loading.vue
<template>
<svg viewBox="25 25 50 50" class="circular">
<circle cx="50" cy="50" r="20" fill="none" class="path"></circle>
</svg>
</template>
<style scoped>
.circular {
height: 42px;
width: 42px;
animation: loading-rotate 2s linear infinite;
}
.path {
animation: loading-dash 1.5s ease-in-out infinite;
stroke-dasharray: 90, 150;
stroke-dashoffset: 0;
stroke-width: 2;
stroke: #409eff;
stroke-linecap: round;
}
@keyframes loading-rotate {
100% {
transform: rotate(1turn);
}
}
@keyframes loading-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -40px;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120px;
}
}
</style>
完善Home页面
home页面首先梳理模块,如下图Home.vue有两个子组件,一个Block2.vue、Block3.vue,在Block3.vue这个页面下有个子列表组件Bitem.vue组件。
当我们了解关系后,下面列举完整代码
Block2.vue页面代码:
<template>
我是异步组件
</template>
Block3.vue
<script setup>
import { getDefineAsyncComponent } from "../utils/index.js";
const Bitem = getDefineAsyncComponent("../components/Bitem.vue");
</script>
<template>
<div v-for="i in 5" :key="i" style="width: 80vw;">
<Bitem class="item-c">
<template #default>
<div>第{{i}}个item</div>
</template>
</Bitem>
</div>
</template>
<style>
.item-c{
width: 100%;
padding: 10px 0;
border: 1px solid #000;
margin-bottom: 5px;
}
</style>
Bitem.vue
<template>
<div >
<slot></slot>
</div>
</template>
Home.vue
<script setup>
import { getDefineAsyncComponent } from "../utils/index.js";
const Block2 = getDefineAsyncComponent("../components/Block2.vue");
import Block3 from '../components/Block3.vue'
</script>
<template>
<div>
<div class="flex-content">
<div class=" left">
<h6>组件1</h6>
</div>
<div class=" right">
<Block2 />
</div>
</div>
<div class="block ">
<h6>下面为异步组件</h6>
</div>
<div class="block big">
<Block3 />
</div>
</div>
</template>
<style scoped>
.block {
margin: 15px;
height: 10vh;
width: 80vw;
border: 1px solid #ebebeb;
border-radius: 3px;
box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6),
0 2px 4px 0 rgba(232, 237, 250, 0.5);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.flex-content {
margin: 15px;
height: 10vh;
width: 80vw;
display: flex;
align-content: center;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
align-items: center;
}
.left {
width: 30%;
height: 100%;
border: 1px solid #ebebeb;
border-radius: 3px;
box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6),
0 2px 4px 0 rgba(232, 237, 250, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.right {
width: 60%;
height: 100%;
border: 1px solid #ebebeb;
border-radius: 3px;
box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6),
0 2px 4px 0 rgba(232, 237, 250, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.big {
height: 50vh;
justify-content: flex-start
}
</style>
在上面的代码中导入工具类,getDefineAsyncComponent,下面讲解工具类的时候会详细将,自此所以页面代码写完了。
工具类
在讲工具类的时候先导入一个插件nprogress,Nprogress 是一个 JavaScript 进度条库,用于显示页面加载和 AJAX 请求的进度。它提供了一个简单的方法来在应用中添加视觉进度指示器。
Nprogress 插件的特点包括:**轻量级:**仅 2KB 大小,不会对页面性能造成显著影响, **易于使用:**通过几个简单的方法即可轻松集成到应用程序中。
npm install nprogress
安装完成后线上完整的代码utils/index.js的代码,再进行讲解
import { defineAsyncComponent, h, } from 'vue';
import Lodaing from "../components/Loading.vue";
import Skeleton from "../components/Skeleton.vue";
import Error from "../components/Error.vue";
import 'nprogress/nprogress.css';
import nProgress from 'nprogress';
nProgress.configure({
trickleSpeed: 50,
showSpinner: false,
});
export function getDefineAsyncComponent(path){
return defineAsyncComponent(
{
loader: async () => {
await delay();
if (Math.random() < 0.5) {
throw new TypeError("加载失败");
}
return import(path);
},
loadingComponent: Skeleton,
errorComponent: {
render() {
return h(Error, "组件加载失败")
}
},
}
)
}
export function getAsyncPage(path){
return defineAsyncComponent(
{
loader: async () => {
nProgress.start();
await delay();
nProgress.done();
return import(path)
},
loadingComponent: Lodaing,
}
)
}
export function delay(duration) {
if (!duration) {
duration = random(1000, 5000);
}
return new Promise((resolove) => {
setTimeout(() => {
resolove(duration)
}, duration);
});
}
export function random(min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
1、引入的依赖
- Vue相关: 使用
defineAsyncComponent从vue库中定义异步组件,h函数用于在渲染函数中创建VNode(虚拟节点)。 - 自定义组件: 引入了
Loading、Skeleton和Error三个Vue组件,分别用于展示加载中、骨架屏和错误提示的UI。 - nprogress: 使用轻量级的进度条库,用于在顶部显示加载进度,通过
nprogress.css和nprogress库引入。
2、配置nprogress
- 使用
nProgress.configure配置了nprogress的行为,设置trickleSpeed(进度条增加的速率)和showSpinner(是否显示加载动画)。
3、定义的函数
getDefineAsyncComponent(path)
- 此函数返回一个通过
defineAsyncComponent定义的异步组件。 - 异步加载时,首先调用
delay函数实现网络延迟加载效果。 - 延迟结束后,模拟网络异常或请求接口失败,通过
Math.random()模拟加载成功或失败的情况。失败时抛出TypeError。 - 加载过程中使用
Skeleton作为加载组件,加载失败时显示自定义的Error组件,并传递了错误信息("组件加载失败")。
getAsyncPage(path)
- 类似于
getDefineAsyncComponent,但专门用于页面级组件的异步加载。 - 在加载前调用
nProgress.start()开始显示进度条,加载完成后调用nProgress.done()隐藏进度条。 - 加载过程中使用
Lodaing(应为Loading)作为加载组件。
delay(duration)
- 一个辅助函数,用于模拟实现网络延迟效果,。
- 如果没有指定
duration,则随机生成一个1000到5000毫秒之间的延迟时间。 - 使用
setTimeout实现延迟,但注意这里resolove是resolve的拼写错误。
random(min, max)
- 生成一个介于
min和max之间的随机整数。
以上解释Vue应用中实现动态加载组件时的加载效果、错误处理和延迟加载功能,整个demo完成。