前言
1. 有关路由懒加载
正常路由的引入方式通常会导致网页首屏加载时间过长,给用户带来不好的体验,所以我们通常使用路由懒加载的方式来引入路由,这样只会在使用到某个路由时才会去加载它,减少了初次加载的时间。
// 正常引入
import TimeKeep from '@/view/TimeKeep.vue'
routes: [
{
path: '/',
redirect: '/time-keep'
},
{
path: '/time-keep',
component: TimeKeep
}
]
// 懒加载
routes: [
{
path: '/',
redirect: '/time-keep'
},
{
path: '/time-keep',
component: () => import('@/view/TimeKeep.vue')
}
]
2. 路由懒加载带来的问题及需求
使用路由懒加载时,访问未访问过的路由时,需要去加载该路由,所以会有明显停顿和等待的时间,然后才切换至该路由,用户体验较差。我希望能够在访问新路由时先进入加载界面,路由加载完毕后隐藏加载界面。在访问过某个路由一次后,该路由就被加载了,再次访问时就不会有停顿的出现,所以我希望加载动画只在首次访问某个路由时出现。
3.有关调试
本地调试时几乎没有延迟,我们可以在控制台模拟较差的网络环境以方便我们调试。
效果
1. 开屏加载
2. 切换路由时加载
3. 切换至已加载过的路由时不会播放加载动画
实现
1. 在App.vue中添加加载界面的结构和样式代码。当然写成组件然后在此引入也是可以的。
<template>
<!-- 加载界面 -->
<Transition name="loading">
<div v-if="loading" class="loader-wrapper">
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
</Transition>
<!-- 主界面 -->
<MainLayout></MainLayout>
</template>
<style scoped>
.loader-wrapper {
position: absolute;
left: 0;
top: 0;
height: 100vh;
width: 100wh;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
}
.loader {
display: inline-block;
width: 30px;
height: 30px;
position: relative;
border: 4px solid #42b883;
animation: loader 2s infinite ease;
}
.loader-inner {
vertical-align: top;
display: inline-block;
width: 100%;
background-color: #42b883;
animation: loader-inner 2s infinite ease-in;
}
// 加载界面动画
@keyframes loader {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(180deg);
}
50% {
transform: rotate(180deg);
}
75% {
transform: rotate(360deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loader-inner {
0% {
height: 0%;
}
25% {
height: 0%;
}
50% {
height: 100%;
}
75% {
height: 100%;
}
100% {
height: 0%;
}
}
.loading-move,
.loading-enter-active,
.loading-leave-active {
transition: all 0.5s ease-in-out;
}
.loading-enter-from,
.loading-leave-to {
opacity: 0 !important;
}
</style>
你可以修改上面的代码将其换成你喜欢的加载动画。这里推荐一个优秀的前端代码片段网站:https://codepen.io/,你可以在里面找到很多炫酷的页面效果。
2. 使用mitt来注册一个全局事件来控制加载界面的显示与否
现在我们写好了加载界面,不过它一直显示在主界面的上方。我们的需求是在初始加载和首次切换至某个路由时显示加载界面。
<script lang="ts" setup>
import { onUnmounted, ref } from 'vue'
import MainLayout from './components/layout/MainLayout.vue'
const loading = ref(true)
// 注册控制加载事件
import emitter from './utils/emitter'
emitter.on('loading', (b) => {
loading.value = b as boolean
})
onUnmounted(() => {
emitter.off('loading')
})
</script>
通过loading变量和条件渲染搭配控制界面的显示,通过调用'loading'全局事件并传入布尔值来修改loading变量的值。loading初始值设置为true
3. 这里使用的emitter需要进行安装和引入。
npm install mitt
新建utils/emitter.ts。内容如下
/**
* emitter
*
* .on 绑定事件
* .off 解绑事件
* .emit 触发事件
*/
import mitt from 'mitt'
const emitter = mitt()
export default emitter
4. 在router配置文件中添加路由守卫, 并创建一个Set集合用于记录已经访问过的路由
import emitter from '@/utils/emitter'
// 创建一个全局状态来管理首次访问状态
const visitedRoutes = new Set()
// 路由守卫
router.beforeEach((to, from, next) => {
if (!visitedRoutes.has(to.path)) {
emitter.emit('loading', true)
}
next()
})
router.afterEach((to) => {
if (!visitedRoutes.has(to.path)) {
visitedRoutes.add(to.path)
emitter.emit('loading', false)
}
})
在路由守卫中进行处理:
- 访问路由前:如果将要访问的路由不在Set集合中,触发全局事件显示加载界面
- 访问路由后:如果当前路由不在Set集合中,将当前路由的path添加至Set集合中,并触发全局事件隐藏加载界面