在加载页面时网页首屏加载时间过长,给用户带来不好的体验,所以我们通常使用加载动画的方式去实现。
加载动画实现原理
首先准备好加载动画和页面内容,之后监听页面的加载状态,如果页面在加载中显示加载动画内容,当页面加载完成后隐藏加载动画部分。
基本实现
1. 创建HTML结构
首先,创建一个基本的HTML结构,包括加载动画的容器和页面内容的容器。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>加载动画示例</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="loader">
<div class="loader-inner"></div>
</div>
<div id="content" class="hidden">
<h1>欢迎来到我的网站</h1>
<p>这里是页面内容...</p>
<!-- 其他页面内容 -->
</div>
<script src="script.js"></script>
</body>
</html>
2. 添加CSS样式
接下来,添加CSS样式来定义加载动画和页面内容的显示方式。
/* styles.css */
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
font-family: Arial, sans-serif;
}
#loader {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #fff;
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
}
.loader-inner {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#content.hidden {
display: none;
}
#content {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
text-align: center;
background-color: #f3f3f3;
}
**3. 添加JavaScript逻辑**
最后,添加JavaScript逻辑来在页面加载完成后隐藏加载动画并显示页面内容。
// script.js
document.addEventListener('DOMContentLoaded', function() {
// 模拟页面加载时间
setTimeout(function() {
// 隐藏加载动画
document.getElementById('loader').classList.add('hidden');
// 显示页面内容
document.getElementById('content').classList.remove('hidden');
}, 2000); // 2秒模拟加载时间,可以根据实际需要调整
});
在vue3中实现
- 在App.vue中添加加载界面的结构和样式代码。当然写成组件然后在此引入也是可以的。
<template>
<!-- 加载界面 -->
<Transition name="loading">
<div v-if="loading" class="loader-wrapper">
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
</Transition>
<!-- 主界面 -->
<router-view></router-view>
</template>
.loader-wrapper {
position: absolute;
left: 0;
top: 0;
height: 100vh;
width: 100vw;
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;
}
2. emitter安装和引入。
npm install mitt
新建utils/emitter.ts。内容如下
import mitt from 'mitt'
const emitter = mitt()
export default emitter
3. 使用mitt来注册一个全局事件来控制加载界面的显示与否
现在我们写好了加载界面,不过它一直显示在主界面的上方。我们的需求是在初始加载和首次切换至某个路由时显示加载界面。
import {
onUnmounted,
ref
} from 'vue';
import emitter from './utils/emitter.js';
const loading = ref(true);
// 确保事件处理函数具有正确的类型
const handleLoading = (a) => {
loading.value = a;
};
// 注册控制加载事件
emitter.on('loading', handleLoading);
onUnmounted(() => {
// 确保 emitter.off 能够正确移除监听器
// 如果 emitter.off 需要特定的回调函数,则使用 handleLoading
emitter.off('loading', handleLoading);
});
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集合中,并触发全局事件隐藏加载界面
版权归原作者 逆旅行天涯 所有, 如有侵权,请联系我们删除。