次源码时代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小时内与您取得联系。