在加载页面时网页首屏加载时间过长,给用户带来不好的体验,所以我们通常使用加载动画的方式去实现。
加载动画实现原理
首先准备好加载动画和页面内容,之后监听页面的加载状态,如果页面在加载中显示加载动画内容,当页面加载完成后隐藏加载动画部分。
基本实现
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中实现
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><!-- 主界面 --><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集合中,并触发全局事件隐藏加载界面