zhanghao 2020-04-21
优点:减少HTTP请求
缺点:
1、代码难以复用
2、使html文件变大,加载事件变长
3、写在html中不利于后期维护。(工程化手段可以解决。源码到可以上线的代码)
优点:
1、很好地复用代码。(有效利用浏览器静态资源缓存)
2、代码分离,利于后期维护。
缺点:增加HTTP请求
首屏代码用内联,其他可以用外联。
css文件放在head里面,越早加载越好。
js文件,没有dom操作的,如屏幕适配,可放head里面。
js文件,有dom操作的,放在body结束前。
//如图片大,可以这样解决:
1、图片压缩处理。使用更高压缩比的图片格式,如webp
2、尽量少用图片。用css画图 或者 用图标字体代替图片。
//如图片多,可以这样解决:
1、合理使用base64内嵌图片。
2、合并图片,如雪碧图。(用时可background-position)
1、避免重复加载css、js文件。
2、上线代码删除注释、空格、换行等。(上线可使用 代码压缩插件 / 在线压缩工具 )
3、使用浏览器缓存。(后端解决)
4、避免多重嵌套。
5、空链接,如 href=" " 或 src=" " 等等,里面最好写上#。避免再发送一次http请求。
6、避免慢标签,如 table 或 iframe等。浏览器会把里面内容全读完后再一次渲染到页面。(读取过程中,网页上有一块空白,读完后一下子出现)
7、主要内容写在前面,次要内容写在后面。
第一种
//dom
<div id="dd" class="dd"></div>
//css
div#dd.dd{} //避免这种情况,虽然更加精确,但是浏览器查找解析慢。
.dd{} //不冲突的情况这样即可第二种
//dom
<div class="aa">
<div class="bb">
<div class="cc"></div>
</div>
</div>
//css
.aa .bb .cc{} //避免这种情况,浏览器会从右到左一个个解析,直到所有条件匹配。而且后面不容易修改,因为这里权重比较高了。
.cc{} //不冲突的情况这样即可第三种
//dom
...
//css
*{ //在项目开发阶段可以用一下,上线代码就尽量不用,因为它会找页面上所有的元素,进行清空内外边距。比较浪费资源
padding:0;
margin:0
}
div,dd,dt{ //可以这样。需要清空哪些元素,就清空
padding:0;
margin:0
}第一种
.cc{
width:100px;
height:100px;
}
.dd{
width:100px;
height:100px;
}
//避免写重复的属性,可以直接这样,把重复的写一块
.cc,.dd{
width:100px;
height:100px;
}第二种
.aa{
margin-top:10px;
margin-right:10px;
margin-bottom:10px;
margin-left:10px;
}
//属性能写一块就写一块,如:
.aa{
margin:10px; //四边都为10px
//margin:10px 10px; //上下 左右
//margin:10px 10px 10px; //上 左右 下
//margin:10px 10px 10px 10px; //上右下左
}1、合理开启gup加速
2、移动端推荐flex,不要滥用float。(float性能消耗比flex多)
3、css中尽量少用@import url(‘base.css‘),因为在加载css中遇到会再发送一次加载base.css的请求。
//dom操作非常消耗性能
三个原则
1、加快单次dom操作。
2、尽量减少dom操作的次数。
3、能用id尽量用id,不要为了使用id而使用id
第一种优化
//dom
<div id="aa">
<div id="bb">123</div>
</div>
//平常获取aa、bb
var aa = document.getElementById(‘aa‘);
var bb = document.getElementById(‘bb‘);
//优化:在获取bb的时候完全不用在document里面找,可以从aa里面找
var bb = aa.getElenentById(‘bb‘);第二种
for(var i=0; i<40; i++){
aa.innerHTML += i;
}
//上面操作dom的次数就达到了40次,非常消耗资源。可以这样
for(var i=0; i<40; i++){
html += i; //字符串操作消耗资源非常低
}
aa.innerHTML = html; //这样操作一次dom就实现了第三种。dom操作中说过
for(var i=0; i<30; i++){
var sp = document.createElement(‘span‘);//创建30次
sp.innerText = i;
aa.appendChild(sp); //渲染30次
}
//这样就执行了30次dom操作了,损耗资源。可以这样
var fragment = document.createDocumentFragment(); //创建虚拟节点对象
var sp = document.createElement(‘span‘); //创建一次span
for(var i=0; i<30; i++){
var span = sp.cloneNode(true); //true表示拷贝sp本身+数据;false表示拷贝sp本身。cloneNode比createElement性能更好
span.innerText = i;
fragment.appendChild(span); //将东西填充到虚拟节点对象里面,虽说填充但是完全不会进行页面渲染
}
aa.appendChild(fragment); //这里只做了一次dom操作第四种
for(var a=0; a<pp.length; a++) //这样的话每一次都用dom获取pp的长度,可以适当将pp.length保存起来。如: for(var a=0,b=pp.length; a<b; a++) //这样性能更好
渲染 = 重排 + 重绘 重排 = 计算网页中各个元素的位置关系 重绘 = 获取元素的样式,将样式绘制到浏览器中 每一次dom的操作都会引发重排/重绘。 引发重排必定引发重绘,引发重绘只是将该元素样式重新绘制一遍
如:
aa.style.fontSize = ‘20px‘; aa.style.color = ‘red‘; aa.style.backgroundColor = ‘green‘; //修改一个以上的样式,建议通过切换class名来进行,切换一次class名就重绘一次 //若像上面直接改变样式可能会引发多次重绘(有些老式浏览器可能得重绘3次)
//善用 事件委托 与 事件节流
//好处,不用循环遍历ul里面的每一项。js事件中有说过
<ul id="ul">
<li class="qq"> one </li>
<li class="qq"> two </li>
<li class="qq"> three </li>
</ul>
var ul = document.getElementById("ul");
ul.addEventListener("click",function(event){
if(event.target.className == "qq") alert("触发了li元素");
},false);//scroll、resize、mousemove、touchmove等等事件每一次都多次触发。只需要触发一次的话可以
var timer = null;
window.addEventListener(‘scroll‘,function(){
clearTimeout(timer);
timer = setTimeout(function(){
console.log("这样就执行一次了");
},100)
},false)1、所有图片src属性路径,都设置成转圈圈gif图。
2、真正需要显示的图片放到一个自定义的属性里,如data-src
3、在需要 按需加载的图片标签,加一个class,如 lazyload-img。这样就可以获取到所有还没加载出来的图片
4、获取所有按需加载的图片集合,并转为数组
var jihe = document.querySelectorAll(‘.lazyload-img‘); //需要使用数组的方法,所以需要转换成数组 var imgArr = Array.prototype.slice.call(jihe); //用这个方法就可以,将类数组转换为数组
5、当页面刚加载进来时,执行一下懒加载,将可视区范围内的图片加载出来
lazyLoadImgs(); //函数稍后定义
6、集合中的图片出现在了可视区范围内,就执行按需加载
var timer = null;
window.addEventListener(‘scroll‘,function(){
clearTimout (timer);
timer = setTimeout(function(){
lazyLoadImg();
},100)
},false)7、lazyLoadImgs函数
function lazyLoadImgs(){
//先遍历集合里面的图片
for(var i=0; i<imgArr.length; i++){
if(isInvisibleArea(imgArr[i])){ //判断当前第i个图片是否在可视区范围内
imgArr[i].src = imgArr[i].getAttribute(‘data-src‘); //若在可视区范围内就将src的转圈图标类名,换成真正的类名
imgArr.splice(i,1); //将当前显示出来图片,从集合里面移除
i--; // [0,1,2,3] 当前下标为0的元素删除,末尾循环会i++,下一次再进入循环i下标1,但是下标为1的的元素变成2了,元素1还没出现过,就会漏掉一个。必须进行i--
}
}
}8、isInvisibleArea函数
function isInvisibleArea(el){ //判断某元素是否在可视区范围内
var rect = el.getBoundingClientRect();
//这样top值小于屏幕宽度,元素就在可视区内;bottom值等于0元素就在可视区外。
return rect.bottom > 0 && rect.top < window.innerHeight; //只要条件成立就返回真
}
//dom中
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div id="a">还没加载到</div>
//css部分
width:300px;
height:300px;
background-color:red;
font-size:30px;
color:white;
//js部分
/*滚动条每动一次就判断一次,该元素是否在可视区内*/
var timer = null;
window.addEventListener(‘scroll‘,jieliu,false)
function jieliu(){
clearTimout (timer);
timer = setTimeout(function(){
panduan(a); //判断函数
},100)
}
function panduan(el){ //判断某元素是否在可视区范围内
var rect = el.getBoundingClientRect();
var jieguo = rect.bottom > 0 && rect.top < window.innerHeight; //只要条件成立就返回真
if(jieguo){ //如果在可视区内就,加载外部js
setTimeout(function () { //延时是为了模仿慢速网络
var script = document.createElement(‘script‘);
script.src = ‘js/loadProduct.js‘;
document.body.appendChild(script); //将引进来的js加载到body中
window.removeEventListener(‘scroll‘, jieliu, false); //执行完成后就可以解绑scroll
}, 3000);
}
}
//外部js
var a = document.getElementById(‘a‘);
a.innerText = "加载到了,真好";当浏览器检测到当前空闲的时候,会把可能需要的资源下载下来。如漫画
var img = new Image(); img.src = ‘./22.jpg‘; //将预加载实际路径赋给img的src属性即可