介绍
Vue3 页面首次进入加载页 友好的实现加载等待
# 加载页的实现思路
- Vue文件的加载顺序是
index.html
-> 请求页面资源 ->App.vue
->页面的其他内容 - 我们可以在
index.html
写一个加载效果 然后当页面请求完毕资源后 在App.vue
中做处理 隐藏在index.html
的加载效果
加载页样式浏览
- 快速浏览效果 地址! (opens new window)
# 实现代码
- 先设置加载的css样式, 创建一个单独的css文件, 后面候通过
<link />
标签进行引用
<!-- 样式 -->
:root {
--main-clr: rgb(0, 127, 255);
--font-clr: rgba(255, 255, 255, 1);
}
#loading-mask {
position: fixed;
left: 0;
top: 0;
user-select: none;
z-index: 2147483647;
overflow: hidden;
background: #2098d1;
transition: 0.55s ease-in-out 0.16s;
height: 100%;
width: 100%;
cursor: wait;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.txt {
position: relative;
top: 3rem;
font-family: sans-serif;
color: var(--font-clr);
}
.support {
width: 2rem;
height: 2rem;
position: absolute;
animation: rotation 3.8s linear infinite;
}
.support:nth-child(1) {
animation-delay: 0.15s;
}
.support:nth-child(2) {
animation-delay: 0.3s;
}
.support:nth-child(3) {
animation-delay: 0.45s;
}
.support:nth-child(4) {
animation-delay: 0.6s;
}
.support:nth-child(5) {
animation-delay: 0.75s;
}
.support:nth-child(6) {
animation-delay: 0.9s;
}
@keyframes rotation {
0% {
opacity: 0.8;
}
30% {
transform: rotate(180deg);
opacity: 1;
}
40% {
transform: rotate(360deg);
opacity: 1;
}
80% {
transform: rotate(720deg);
opacity: 0.8;
}
81% {
opacity: 0;
}
100% {
transform: rotate(0deg);
opacity: 0;
}
}
.dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--font-clr);
position: relative;
top: 37px;
left: 7px;
}
.loadingapp {
opacity: 0;
}
- 按照浏览器执行的上下文方式, 强烈建议把css的文件放入 (opens new window) 进行引用, 这样可以提前引用到css样式表
<link />
引用css样式表时候, 需要把rel (opens new window) 属性设置为stylesheet
, css文本属性<script>
引用js的逻辑代码, 注意:不允许标签省略, 开始标签和结束标签都不能省略, 必须<script> </script>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<!-- 导入加载css -->
<link rel="stylesheet" href="./loading.css" referrerpolicy="origin" />
<!-- 导入jq -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- 导入gsap动画库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.4/gsap.min.js"
integrity="sha512-f8mwTB+Bs8a5c46DEm7HQLcJuHMBaH/UFlcgyetMqqkvTcYg4g5VXsYR71b3qC82lZytjNYvBj2pf0VekA9/FQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<style>
</style>
</head>
- 通过jq的
$(document).ready()
, 来判断页面是否加载成功(类似于vue3的onMounted
), 再通gsap.to() (opens new window)设置一个隐藏的动画(opacity: 0
), 最后通过onComplete
隐藏动画结束后设置pointer-events: none
穿透点击和z-index: -1
降低层级, 或者直接给个display: none
也可以
<script>
$(document).ready(
gsap.to("#loading-mask", {
opacity: 0, ease: "elastic", delay: 0.5, ease: 'power2.out', onComplete: () => {
$("#loading-mask").css("pointer-events", "none").css("z-index", "-1");
// $("#loading-mask").css("display", "none")
}
})
)
</script>
- 完整的html代码
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<!-- 导入加载css -->
<link rel="stylesheet" href="./loading.css" referrerpolicy="origin" />
<!-- 导入jq -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- 导入gsap动画库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.4/gsap.min.js"
integrity="sha512-f8mwTB+Bs8a5c46DEm7HQLcJuHMBaH/UFlcgyetMqqkvTcYg4g5VXsYR71b3qC82lZytjNYvBj2pf0VekA9/FQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
<style>
</style>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<!-- 设置加载页 -->
<div id="loading-mask">
<div class="container">
<div class="support">
<div class="dot"></div>
</div>
<div class="support">
<div class="dot"></div>
</div>
<div class="support">
<div class="dot"></div>
</div>
<div class="support">
<div class="dot"></div>
</div>
<div class="support">
<div class="dot"></div>
</div>
<div class="support">
<div class="dot"></div>
</div>
<p class="txt">Please wait</p>
</div>
</div>
<!-- 内容页 -->
<div id="app" />
<!-- built files will be auto injected -->
</body>
<script>
$(document).ready(
gsap.to("#loading-mask", {
opacity: 0, ease: "elastic", delay: 0.5, ease: 'power2.out', onComplete: () => {
$("#loading-mask").css("pointer-events", "none").css("z-index", "-1");
// $("#loading-mask").css("display", "none")
}
})
)
</script>
</html>
# 注意问题
- 在苹果的
safari
浏览器中 会出现无法选中index.html
中 除app
以外的Dom 我们只能通过其他方式 实现首次加载页
# 备注
- 我们注意到 可以用两种方式 实现页面加载完毕后 取消加载页 这两种生命周期有什么不同呢
Vue的 onMounted
原理:
- 和jq的
document.ready
一样 表示文档结构已经加载完成(不包含图片 字体 等非文字媒体文件)DOM结构绘制完成之后就会执行,这样能确保就算有大量的媒体文件没加载出来,JS代码一样可以执行。可以配合nextTick
缺点:
onMounted
的缺点很少 但是基于DOM结构绘制完成之后就会执行 并非所有网页资源已请求到 如果用户的网络很差 或者服务器延迟很高 那么不光字体和图片延迟显示 也会导致页面陷入空白 直到需要的js和css文件请求完毕后 才会显示 对于网络要求较高
原生方法 window.onload
原理:
- 指示页面包含图片等文件在内的所有元素都加载完成。必须等到网页中所有内容全部加载完毕之后才被执行(包含图片 字体 等非文字媒体文件)。如果一个网页中有大量的图片的话,则就会出现这种情况:网页文档已经呈现出来,但由于网页数据还没有完全加载完毕,导致load事件不能够即时被触发(懒加载可以解决哦)
缺点:
- 虽然懒加载可以解决图片加载问题 依旧需要请求文字等文件 等全部加载完毕后 才会显示完整的页面 这样虽然会让页面显示的很全面 但是无疑会增加用户加载时间
总结
onMounted
的工作原理 类似于异步操作 当Dom结构绘制完毕后 就会执行 并不会管页面的js或者css等资源是否请求完毕 给用户的页面是需要加载的 (图片 字体等)window.onload
的工作原理 类似于同步操作 全部资源都请求到位 才会执行 这样给用户的页面就是最完整的页面