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属性即可