對於一些比較大的web項目來說,網站加載較長時,會出現時間長短不一的白屏,想要讓用戶知道,這個網頁是有反應的,給個加載的畫面提示,以免損失客戶流量,現在以vue
開發的項目為例。
在此之前,希望讀者是有了解過vue的,最好是有用過vue的腳手架構建過項目的。
在vue項目中,只有一個html文件,我們要找的就是這個,在vue-cli3
生成的項目中,index.html在public文件夾里。
初始化時的index.html文件是這樣的
<!DOCTYPE html>
<html lang="en">
<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, viewport-fit=cover" >
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</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="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
其中<div id="app"></div>
就是整個單頁面應用的入口,會在數據加載完才顯示,這個時候只要在其上面寫上HTML代碼就可以在網站還沒加載完成時,把自己寫的加載動畫顯示出來了,在網站加載完成時,把自己寫的HTML代碼移除掉,所以這里需要知道如何才能知道,網站已經加載好了。
主要是利用onreadystatechange
事件,這個稍后再說,先看下添加的h5代碼與CSS樣式
在<div id="app"></div>
上面添加
<div id="loading">
<div class="div" style="animation: myAnima 1s infinite">
<div class="div1"></div>
<div class="small-black">
<div class="very-small-white"></div>
</div>
<div class="small-white">
<div class="very-small-black"></div>
</div>
</div>
<div class="progress-box margin-top">
<div class="progress"></div>
</div>
<p class="p margin-top">正在玩命加載</p>
</div>
<!-- <div id="app"></div> 添加在上面 -->
接下來是上面H5代碼的CSS樣式
<style>
#loading{
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
#loading .div{
width: 160px;
height: 160px;
background-color: #000000;
position: relative;
border-radius: 50%;
transform: rotate(10deg);
}
#loading .div .div1{
width: 80px;
height: 160px;
background-color: #ffffff;
border-radius: 80px 0 0 80px;
}
#loading .div .small-black{
position: absolute;
bottom: 0;
left: 40px;
width: 80px;
height: 80px;
background-color: #000000;
border-radius: 50%;
}
#loading .div .small-white{
position: absolute;
top: 0;
left: 40px;
width: 80px;
height: 80px;
background-color: #ffffff;
border-radius: 50%;
}
#loading .div .small-black .very-small-white{
position: absolute;
top: 25px;
left: 25px;
width: 30px;
height: 30px;
background-color: #ffffff;
border-radius: 50%;
}
#loading .div .small-white .very-small-black{
position: absolute;
top: 25px;
left: 25px;
width: 30px;
height: 30px;
background-color: #000000;
border-radius: 50%;
}
#loading .margin-top{
margin-top: 20px;
}
#loading .progress-box{
width: 300px;
height: 20px;
border: 1px solid #ababab;
position: relative;
}
#loading .progress-box .progress{
position: absolute;
top: 0;
bottom: 0;
left: 0;
background-color: #1989fa;
width: 0;
}
@keyframes myAnima{
0% {transform: rotate(0deg)}
10% {transform: rotate(36deg)}
20% {transform: rotate(72deg)}
30% {transform: rotate(108deg)}
40% {transform: rotate(144deg)}
50% {transform: rotate(180deg)}
60% {transform: rotate(216deg)}
70% {transform: rotate(252deg)}
80% {transform: rotate(288deg)}
90% {transform: rotate(324deg)}
100% {transform: rotate(360deg)}
}
</style>
最后是js代碼,這里要注意的是,這部分代碼要放在<head><head>
中,不能放在<body><body>
中,因為只有這樣,這部分代碼才會在<div id="app"></div>
加載完成之前執行。
<script>
let time = null; // 接收定時器返回的標識
//這個函數用於進度條的變化和文字的變化
function loop(){
let num = parseInt(Math.random()*100);
const progress = document.querySelector('.progress');
progress.style.width = num + '%';
const p = document.querySelector('.p');
p.innerText = '正在玩命加載' + num + '%';
}
//定時器
if(!time){
time = setInterval(()=>{
loop();
}, 100);
}
document.onreadystatechange = completeLoading;
function completeLoading() {
if (document.readyState == "complete") {
clearInterval(time);
time = null;
const loading = document.querySelector('#loading');
loading.remove();
}
}
</script>
好了,主要來看這部分代碼
document.onreadystatechange = completeLoading;
function completeLoading() {
if (document.readyState == "complete") {
clearInterval(time);
time = null;
const loading = document.querySelector('#loading');
loading.remove(); //刪除元素
}
}
onreadystatechange
這個是ajax的一個事件。
當請求被發送到服務器時,可能有時候需要執行一些事件,每當readyState
改變時,就會觸發onreadystatechange
事件。
document.readyState
描述文檔的加載狀態,有三個值:
- loading / 正在加載
- document仍在加載
- interactive / 可交互
- 文檔已被解析,"正在加載"狀態結束,但是諸如圖像,樣式表和框架之類的子資源仍在加載。
- complete / 完成
- 文檔和所有子資源已完成加載。表示
load
狀態的事件即將被觸發。
- 文檔和所有子資源已完成加載。表示
當這個屬性改變時,就會觸發onreadystatechange
事件
當確定加載完成時,就可以讓定時器清除定時器了,並且刪除用於展示加載動畫的元素了
完整代碼
<!DOCTYPE html>
<html lang="en">
<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, viewport-fit=cover" >
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<style>
#loading{
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
#loading .div{
width: 160px;
height: 160px;
background-color: #000000;
position: relative;
border-radius: 50%;
transform: rotate(10deg);
}
#loading .div .div1{
width: 80px;
height: 160px;
background-color: #ffffff;
border-radius: 80px 0 0 80px;
}
#loading .div .small-black{
position: absolute;
bottom: 0;
left: 40px;
width: 80px;
height: 80px;
background-color: #000000;
border-radius: 50%;
}
#loading .div .small-white{
position: absolute;
top: 0;
left: 40px;
width: 80px;
height: 80px;
background-color: #ffffff;
border-radius: 50%;
}
#loading .div .small-black .very-small-white{
position: absolute;
top: 25px;
left: 25px;
width: 30px;
height: 30px;
background-color: #ffffff;
border-radius: 50%;
}
#loading .div .small-white .very-small-black{
position: absolute;
top: 25px;
left: 25px;
width: 30px;
height: 30px;
background-color: #000000;
border-radius: 50%;
}
#loading .margin-top{
margin-top: 20px;
}
#loading .progress-box{
width: 300px;
height: 20px;
border: 1px solid #ababab;
position: relative;
}
#loading .progress-box .progress{
position: absolute;
top: 0;
bottom: 0;
left: 0;
background-color: #1989fa;
width: 0;
}
@keyframes myAnima{
0% {transform: rotate(0deg)}
10% {transform: rotate(36deg)}
20% {transform: rotate(72deg)}
30% {transform: rotate(108deg)}
40% {transform: rotate(144deg)}
50% {transform: rotate(180deg)}
60% {transform: rotate(216deg)}
70% {transform: rotate(252deg)}
80% {transform: rotate(288deg)}
90% {transform: rotate(324deg)}
100% {transform: rotate(360deg)}
}
</style>
<script>
let time = null;
function loop(){
let num = parseInt(Math.random()*100);
const progress = document.querySelector('.progress');
progress.style.width = num + '%';
const p = document.querySelector('.p');
p.innerText = '正在玩命加載' + num + '%';
}
if(!time){
time = setInterval(()=>{
loop();
}, 100);
}
document.onreadystatechange = completeLoading;
function completeLoading() {
if (document.readyState == "complete") {
clearInterval(time);
time = null;
const loading = document.querySelector('#loading');
loading.remove();
}
}
</script>
</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">
<div class="div" style="animation: myAnima 1s infinite">
<div class="div1"></div>
<div class="small-black">
<div class="very-small-white"></div>
</div>
<div class="small-white">
<div class="very-small-black"></div>
</div>
</div>
<div class="progress-box margin-top">
<div class="progress"></div>
</div>
<p class="p margin-top">正在玩命加載</p>
</div>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>