次源碼時代H5學科老師跟大家一起來總結下在web應用中常見的加載進度條實現方案。
隨著html5的普及,各種css3動畫及js特效在網頁中也是層出不窮,PC端加載數據的速度還是比較快的,但是對于移動端設備而言則相對要慢不少,如果圖片或者腳本沒有加載完,用戶在操作中就可能發生各種問題,因此我們需要對數據加載進行偵測,以更加人性化的方法將網頁程序內容展現給用戶,實現更佳的用戶體驗。
先說一下整體的實現思路吧,常見的效果是將進度條的dom結構顯示在頁面最“前”(使用fixed定位 + 高z-index,提高優先級),主體內容相當于是被“隱藏”(實際是被遮蓋)了,所以進度條一打開網頁就有了,當網頁內容全部加載完成后,觸發js相關事件,執行回調函數:隱藏進度條的同時顯示頁面主體內容。
【1. 定時器模擬制作進度條】
很多同學會使用定時器的方式實現網頁進度條,通常可以設置延遲3到5秒鐘的時間后來顯示網頁內容,這樣的確可以模擬出進度條的加載效果,不過這種方式會有一些問題,比如當前頁面已經打開過了,瀏覽器中會有緩存數據,再次開啟頁面定時器依然會執行,反而會影響加載性能,原本可以“瞬間”完成的內容加載,現在由于定時器的原因也需要等待。還有一個就是在網絡情況比較糟糕的情況下,很有可能3到5秒鐘的時間也未必能夠加載完成網頁內容,這個時候定時器加載又顯得比較雞肋了。
示例代碼參考:load1.html
樣式:
<font size="3"><style type="text/css">
*{
margin: 0;
padding: 0;
}
#Loading{
position: fixed;
width: 100%;
height: 100%;
background-color: orange;
color: #fff;
font-size: 40px;
text-align: center;
line-height: 10;
}
</style></font>
復制代碼
結構:
<font size="3"><!--加載頁面-->
<div id="Loading">loading...</div>
<!--內容主體-->
<div id="Cont">Hello world</div></font>
復制代碼
交互:
<font size="3"><script>
var load_page = document.querySelector("#Loading");
setTimeout(function(){
load_page.style.display = "none";
}, 3000)
</script></font>
復制代碼
小結:
1. 定時器模擬制作進度條只能是視覺表現上的實現,而非真正意義上的解決方案。
【2. 通過加載狀態事件制作進度條】
javascrip提供了相關事件機制可以監控頁面的加載情況,我們可以通過加載狀態事件實現進度條的制作,可以使用window.onload事件,等到頁面中全部內容包括圖片加載完成后才會被觸發,或者使用document.onReadyStateChange事件,在ReadyStateChange事件中可通過自變量事件參數獲取到頁面加載的當前狀態,分為5項內容:
Uninitialized:未初始化
Loading:載入
Loaded:載入完成
Interactive:交互
Completed:完成
而js通過ReadyStateChange事件可以獲取到的僅為后2項狀態,不過對于我們的代碼實現而言僅僅只需要最后一個完成狀態即可。
示例代碼參考:load2.html(樣式代碼同load1.html)
結構:
<font size="3"><!--加載頁面-->
<div id="Loading">
loading...
</div>
<!--內容主體-->
<div id="Cont">
<p>Hello world</p>
<img src="http://img.hb.aicdn.com/0b452ed716f0530575eff4b4e253009af7112a19bbec-Cg9NH6"/>
<img src="http://img.hb.aicdn.com/80701a6a3be8f6ce71a312385d672963f155b7627542e-qfEGEw"/>
<img src="http://img.hb.aicdn.com/8cfc2f27f9832043e3dcb87512ce6c56a8e54fed5a905-skDixu"/>
</div></font>
復制代碼
交互:
<font size="3"><script>
var load_page = document.querySelector("#Loading");
document.onreadystatechange = function(e){
if(e.target.readyState === "complete"){
load_page.style.display = "none";
}
}
</script></font>
復制代碼
小結:
1. 通過加載狀態事件(window.onload或document.onreadystatechange)制作進度條,可真正意義上實現頁面加載效果。
【3. 實時獲取加載數據制作進度條】
通過加載狀態事件制作進度條,可真正意義上實現頁面加載效果,但是無法顯示當前加載進度,當內容加載完成后直接就顯示出了落地頁,過程中缺少了加載進度提示,實際上對于網頁而言加載圖片之類的二進制資源文件是最大的加載開銷,所以通常來講圖片資源往往是最后加載完成的,其加載行為本身又是異步的,所以我們可以通過圖片自身的load事件判定其是否加載完成,執行回調函數實時計算加載進度,模擬實時獲取加載數據進度條效果。
示例代碼參考:load3.html(樣式代碼同load1.html)
結構:
<font size="3"><!--加載頁面-->
<div id="Loading">
<p>loading...</p>
<h2>0%</h2>
</div>
<!--內容主體-->
<div id="Cont">
<p>Hello world</p>
<img src="http://img.hb.aicdn.com/0b452ed716f0530575eff4b4e253009af7112a19bbec-Cg9NH6"/>
<img src="http://img.hb.aicdn.com/80701a6a3be8f6ce71a312385d672963f155b7627542e-qfEGEw"/>
<img src="http://img.hb.aicdn.com/8cfc2f27f9832043e3dcb87512ce6c56a8e54fed5a905-skDixu"/>
<img src="http://img.hb.aicdn.com/c6572538c319c2096425485d27333153ab6a4237882c4-vb7X0I"/>
<img src="http://img.hb.aicdn.com/6d43fa49d2bdfa8379150ccb28991b4377a77a394f483-5iZuD5"/>
<img src="http://img.hb.aicdn.com/14b5365bb3462895b936d08afef904e7aa665cfa2a616-eHgU0g"/>
<img src="http://img.hb.aicdn.com/29922a9799e1c29f8a5ab92b79724bd558f9d4f548ea3-xXw31P"/>
<img src="http://img.hb.aicdn.com/b4c55ba8355ac8778752029cc853a6a41e0057e16d2e0-OGreNB"/>
<img src="http://img.hb.aicdn.com/d7075bfa3490f842ca2d7f28df14ca31973052a93fd7ea-nvZYmh"/>
<img src="http://img.hb.aicdn.com/69dea0ffbc98b8a8238d611a931bf10f1b12ba6b65743-dR6cTv"/>
</div></font>
復制代碼
交互:
<font size="3"><script>
var load_page = document.querySelector("#Loading"),
h2 = document.querySelector("h2"),
imgs = document.querySelectorAll("img"),
imgs_len = imgs.length,
loaded = 0,
load_callback = function(){
loaded++;
h2.innerHTML = parseInt(loaded/imgs_len*100) + "%";
if(loaded === imgs_len) load_page.style.display = "none";
};
for(var i=0; i<imgs_len; i++){
if(imgs[i].complete == true){//圖片已加載完成
load_callback();
}else{
imgs[i].onload = function(){//圖片動態加載完成觸發
load_callback();
}
}
}
</script></font>
復制代碼
網站資源擴展:
1. 動畫圖標資源:www.loading.io
2. GIF預加載圖標資源:www.preloaders.net
感謝源碼時代H5學科講師提供此文章!
本文為原創文章,轉載請注明出處(http://www.itsource.cn)!
覽器加載一個js腳本,會在devtools中留下各種痕跡,elements中的script元素,console中的日志,source中的代碼,network中的網絡請求等
這個比較簡單,插入js的時候設置好id,在js中刪掉自身就好了
<script id="xxx">
// todo
document.getElementById("xxx").remove();
</script>
對于引用js
<script id="xxx" src="a.js"></script>
// a.js
document.getElementById("xxx").remove()
對于動態加載的js也是一樣的
<script>
let e=document.createElement("script");
e.id="xxx";
e.src="a.js";
document.head.appendChild(e);
</script>
// a.js
document.getElementById("xxx").remove()
或者也可以這樣
<script>
let e=document.createElement("script");
e.src="a.js";
document.head.appendChild(e);
e.remove();
</script>
雖然看起來很奇怪,但a.js確實能執行,似乎是加載a.js時阻塞了腳本執行,執行完a.js之后再remove
clear就好了
console.clear()
直接引用和動態加載都會在source中出現
<script src="a.js"></script>
<script>
let e=document.createElement("script");
e.src="a.js";
document.head.appendChild(e);
</script>
這樣都是不行的,經過測試發現動態插入js代碼時不會被記錄在source中
<script>
fetch("a.js").then(resp => {
return resp.text()
}).then(text => {
let e = document.createElement("script");
e.innerHTML = text;
document.head.appendChild(e);
})
</script>
這樣a.js就不會出現在source里了
常規HTTP/WebSocket都會被記錄,無法繞過,但是WebRTC不會,WebRTC可以基于UDP/TCP傳輸,WebRTC提供createDataChannel API,可以用于傳輸文本,那么就可以實現network隱藏加載
考慮WebRTC需要傳遞offer和icecandidate,還是得通過HTTP/WebSocket傳輸,而且復雜網絡環境下還需要使用或部署STUN/TURN服務器,穩定性有待考慮
WebRTC技術可以參考學習我最近看的幾篇文章透明日報20200801期
其他的方法我還沒有找到,技術不行就社會工程
一個思路是可以偽裝成其他流量混過去,比如png
<script>
fetch("a.png").then(resp => {
return resp.text()
}).then(text => {
let e = document.createElement("script");
e.innerHTML = text;
document.head.appendChild(e);
})
</script>
然后在delvtools里也看不出來
另外一個思路是devtools目前只在打開的時候記錄network數據,那么只要在devtools關閉的時候加載資源,打開就不加載,這樣就不會出現在network里了
新的問題又出現了,如何檢測devtools的狀態,網上已經有不少公開技巧了
https://github.com/sindresorhus/devtools-detect
https://github.com/AEPKILL/devtools-detector
還可以在哪里找到加載和執行痕跡呢
還有什么方法可以隱藏這些痕跡呢
如果你現在也想學習前端開發技術,在學習前端的過程當中有遇見任何關于學習方法,學習路線,學習效率等方面的問題,你都可以申請加入我的Q群:前114中6649后671還有大牛整理的一套高效率學習路線和教程與您免費分享,還有許多大廠面試真題。希望能夠對你們有所幫助。
下代碼來源 https://tobiasahlin.com/spinkit/
為了怕源文件刪除,我抄錄了幾個.....
//html
<div class="spinner"></div>
//css
.spinner {
width: 40px;
height: 40px;
background-color: #333;
margin: 100px auto;
-webkit-animation: sk-rotateplane 1.2s infinite ease-in-out;
animation: sk-rotateplane 1.2s infinite ease-in-out;
}
@-webkit-keyframes sk-rotateplane {
0% { -webkit-transform: perspective(120px) }
50% { -webkit-transform: perspective(120px) rotateY(180deg) }
100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) }
}
@keyframes sk-rotateplane {
0% {
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)
} 50% {
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)
} 100% {
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
}
//html
<div class="sk-chase">
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
<div class="sk-chase-dot"></div>
</div>
//css
.sk-chase {
width: 40px;
height: 40px;
position: relative;
animation: sk-chase 2.5s infinite linear both;
}
.sk-chase-dot {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
animation: sk-chase-dot 2.0s infinite ease-in-out both;
}
.sk-chase-dot:before {
content: '';
display: block;
width: 25%;
height: 25%;
background-color: #fff;
border-radius: 100%;
animation: sk-chase-dot-before 2.0s infinite ease-in-out both;
}
.sk-chase-dot:nth-child(1) { animation-delay: -1.1s; }
.sk-chase-dot:nth-child(2) { animation-delay: -1.0s; }
.sk-chase-dot:nth-child(3) { animation-delay: -0.9s; }
.sk-chase-dot:nth-child(4) { animation-delay: -0.8s; }
.sk-chase-dot:nth-child(5) { animation-delay: -0.7s; }
.sk-chase-dot:nth-child(6) { animation-delay: -0.6s; }
.sk-chase-dot:nth-child(1):before { animation-delay: -1.1s; }
.sk-chase-dot:nth-child(2):before { animation-delay: -1.0s; }
.sk-chase-dot:nth-child(3):before { animation-delay: -0.9s; }
.sk-chase-dot:nth-child(4):before { animation-delay: -0.8s; }
.sk-chase-dot:nth-child(5):before { animation-delay: -0.7s; }
.sk-chase-dot:nth-child(6):before { animation-delay: -0.6s; }
@keyframes sk-chase {
100% { transform: rotate(360deg); }
}
@keyframes sk-chase-dot {
80%, 100% { transform: rotate(360deg); }
}
@keyframes sk-chase-dot-before {
50% {
transform: scale(0.4);
} 100%, 0% {
transform: scale(1.0);
}
}
*請認真填寫需求信息,我們會在24小時內與您取得聯系。