做前端的时候,把实现不了的效果切换成图片还有一些图标也会切成图片,会降低前端页面展示的性能,增加页面资源HTTP的请求负担,甚至有的页面存在几十个img
的http
请求 。
首先我们目前常用的图片格式有png,gif,jpg等
是降低图片的大小kb,有很多方法可以做,压缩图片,选择更小kb的图片格式,以达到最优的显示效果
- 智图:一个图片优化平台
- https://tinypng.com/
不管是pc还是移动端,都会有很多不同尺寸的图片,如果你做的是响应式网站和移动端的话,那么你就更需要考虑图片尺寸的选择问题了
移动端的屏幕分辨率和尺寸太多,所以就可能需要不同的尺寸加载不同尺寸的图片,这样就节省了网站的访问流量,以及页面渲染的效率比如PC的版心都是1200左右,如果在手机上肯定是不需要这么大的,这个时候就。。。。
先展示现在设备的分辨率等的图
CSSSprites(背景精灵图/雪碧图)
一种网页图片应用处理方式,将一个页面涉及到的所有零星图片或者图标都包含到一张大图里面,这样就只需要加载这个一个图片,而不是很多个图片了,这样就减少了很多
http
的请求。
随着技术的更新和浏览器的更新,字体图库去代替一些图标我认为还是极好的,使用字体图库你不仅可以改变大小,而且还可以改变颜色
比较熟知的的字体图库有很多,
- font-awesom
- icoMoon
一、什么是图片滚动加载?
通俗的讲就是:当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。
二、为什要使用这个技术?
比如一个页面中有很多图片,如淘宝、京东首页等等,如果一上来就发送这么多请求,页面加载就会很漫长,如果js文件都放在了文档的底部,恰巧页面的头部又依赖这个js文件,那就不好办了。更为要命的是:一上来就发送百八十个请求,服务器可能就吃不消了(又不是只有一两个人在访问这个页面)。
我们可以通过给img自定义一个新属性,来存储图片真实的src地址,当需要加载的时候,再将这个真实的地址赋给src,进行图片加载。
所以大体的思路为:
想到这一步,整体的大概思路(demo.html)
:
此时,判断目标标签是否已经出现在视野中的思路为:
分析标签出现在页面中的两个临界状态:
当页面向上滚动,一直滚到首先出现在页面的下边缘的时候,此时有页面向上滚动的距离,加上浏览器自身的高度,就等于目标标签本身在页面中距离页面顶部的距离。
页面接着向上滚,当页面出现在了浏览器的上边沿的时候,此时页面向上滚的高度,就等于目标标签本身在页面中距离页面顶部的距离
那么可以checkShow函数可以写为:
.offset()方法允许我们检索一个元素 (包含其 border 边框,不包括 margin) 相对于文档(document)的当前位置。
.offset()返回一个包含top 和 left属性的对象 。表示相对于顶部或者左边的坐标。
// 传入一个img的jq对象
function checkShow($img) {
//即页面向上滚动的距离,$(window) 就是你浏览的当前浏览器的窗口
var scrollTop = $(window).scrollTop();
// 浏览器自身的高度
var windowHeight = $(window).height();
//目标标签img相对于document顶部的位置
var offsetTop = $img.offset().top;
//在2个临界状态之间的就为出现在视野中的
if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) {
return true;
}
return false;
}
function isLoaded ($img) {
//如果data-src和src相等那么就是已经加载过了
return $img.attr('data-src') === $img.attr('src');
}
function loadImg ($img) {
$img.attr('src',$img.attr('data-src'));
// 加载就是把自定义属性中存放的真实的src地址赋给src属性
}
(第1次优化.html)
首先有个明显的问题,目前页面上,第一次进来的时候如果不滚动滚轮的话什么都看不到,想修复这个问题,可以先进行一次页面检查,调用checkShow(),然后页面上在视野中的标签就会被加载,然后再进行监听window的scroll事件。
<head>
<meta charset="UTF-8">
<title>图片懒加载-简单title>
<script src="../js/jquery-1.8.3.js">script>
<style>
ul,li {
list-style: none;
}
.container {
width: 600px;
margin: 0 auto;
}
.container li {
float: left;
margin: 10px 10px;
}
.container li img {
width: 240px;
height: 180px;
}
p {
float: left;
}
style>
head>
<body>
<ul class="container">
<li><a href="#"><img src="" data-src="../images/01.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/02.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/03.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/04.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/05.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/06.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/07.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/08.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/09.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/10.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/11.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/12.png" />a>li>
<li><a href="#"><img src="" data-src="../images/13.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/14.png" />a>li>
<li><a href="#"><img src="" data-src="../images/15.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/16.jpg" />a>li>
ul>
<script>
// 必须手动先先进行一次检查才行
$('.container img').each(function () {
if (checkShow($(this)) && !isLoaded($(this))) {
loadImg($(this));
}
});
$(window).on('scroll', function () {
//当页面滚动的时候绑定事件
$('.container img').each(function () {//遍历所有的img标签
if (checkShow($(this)) && !isLoaded($(this))) { // 需要写一个checkShow函数来判断当前img是否已经出现在了视野中
//还需要写一个isLoaded函数判断当前img是否已经被加载过了
loadImg($(this));
//符合上述条件之后,再写一个加载函数加载当前img
}
})
});
function checkShow($img) { // 传入一个img的jq对象
var scrollTop = $(window).scrollTop(); //即页面向上滚动的距离
var windowHeight = $(window).height(); // 浏览器自身的高度
var offsetTop = $img.offset().top; //目标标签img相对于document顶部的位置
if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) { //在2个临界状态之间的就为出现在视野中的
return true;
}
return false;
}
function isLoaded($img) {
return $img.attr('data-src') === $img.attr('src'); //如果data-src和src相等那么就是已经加载过了
}
function loadImg($img) {
$img.attr('src', $img.attr('data-src')); // 加载就是把自定义属性中存放的真实的src地址赋给src属性
}
script>
body>
(第2次优化.html)
但是此时代码有重复的,进行优化。将重复的代码块写成一个新的函数。进行替换。
<head>
<meta charset="UTF-8">
<title>图片懒加载-简单title>
<script src="../js/jquery-1.8.3.js">script>
<style>
ul, li {
list-style: none;
}
.container {
width: 600px;
margin: 0 auto;
}
.container li {
float: left;
margin: 10px 10px;
}
.container li img {
width: 240px;
height: 180px;
}
p {
float: left;
}
style>
head>
<body>
<ul class="container">
<li><a href="#"><img src="" data-src="../images/01.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/02.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/03.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/04.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/05.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/06.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/07.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/08.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/09.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/10.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/11.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/12.png" />a>li>
<li><a href="#"><img src="" data-src="../images/13.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/14.png" />a>li>
<li><a href="#"><img src="" data-src="../images/15.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/16.jpg" />a>li>
ul>
<script>
// 先进行一次检查
//去掉多余的部分,降低耦合性
lazyRender();
$(window).on('scroll', function () {
console.log('运行了一次');
lazyRender();
});
function lazyRender() {
$('.container img').each(function () {
if (checkShow($(this)) && !isLoaded($(this))) {
loadImg($(this));
}
})
}
function checkShow($img) { // 传入一个img的jq对象
var scrollTop = $(window).scrollTop(); //即页面向上滚动的距离
var windowHeight = $(window).height(); // 浏览器自身的高度
var offsetTop = $img.offset().top; //目标标签img相对于document顶部的位置
if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) { //在2个临界状态之间的就为出现在视野中的
return true;
}
return false;
}
function isLoaded($img) {
return $img.attr('data-src') === $img.attr('src'); //如果data-src和src相等那么就是已经加载过了
}
function loadImg($img) {
$img.attr('src', $img.attr('data-src')); // 加载就是把自定义属性中存放的真实的src地址赋给src属性
}
script>
body>
(第3次优化.html)
代码优化已经很好了,对于性能的优化:
$(window).on(‘scroll’,function () {}这个事件鼠标滚动的时候触发次数非常多。对性能影响大,优化思路是当鼠标滚轮停止滚动的时候,再去判定是否存在在视野中,而不是滚动过程中一直触发。
<head>
<meta charset="UTF-8">
<title>图片懒加载-简单title>
<script src="../js/jquery-1.8.3.js">script>
<style>
ul, li {
list-style: none;
}
.container {
width: 600px;
margin: 0 auto;
}
.container li {
float: left;
margin: 10px 10px;
}
.container li img {
width: 240px;
height: 180px;
}
p {
float: left;
}
style>
head>
<body>
<ul class="container">
<li><a href="#"><img src="" data-src="../images/01.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/02.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/03.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/04.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/05.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/06.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/07.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/08.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/09.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/10.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/11.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/12.png" />a>li>
<li><a href="#"><img src="" data-src="../images/13.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/14.png" />a>li>
<li><a href="#"><img src="" data-src="../images/15.jpg" />a>li>
<li><a href="#"><img src="" data-src="../images/16.jpg" />a>li>
ul>
<script>
// 先进行一次检查
lazyRender();
//为了不在滚轮滚动过程中就一直判定,设置个setTimeout,等停止滚动后再去判定是否出现在视野中。
var clock; //这里的clock为timeID, 返回一个 ID(数字),可以将这个ID传递给 clearTimeout() 来取消执行。
$(window).on('scroll', function () {
// lazyRender();
if (clock) { //只要在300毫秒内触发滚动事件,都会被clearTimeout掉,setTimeout不会执行。
//如果有300毫秒外的操作,会得到一个新的timeID即clock,会执行一次setTimeout,然后保存这次setTimeout的ID,
//对于300毫秒内的scroll事件,不会生成新的timeID值,所以会一直被clearTimeout掉,不会执行setTimeout.
clearTimeout(clock);
// console.log(clock, 1111);
}
clock = setTimeout(function () {
console.log('运行了一次');
lazyRender();
}, 300)
});
function lazyRender() {
$('.container img').each(function () {
if (checkShow($(this)) && !isLoaded($(this))) {
loadImg($(this));
}
})
}
function checkShow($img) { // 传入一个img的jq对象
var scrollTop = $(window).scrollTop(); //即页面向上滚动的距离
var windowHeight = $(window).height(); // 浏览器自身的高度
var offsetTop = $img.offset().top; //目标标签img相对于document顶部的位置
if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) { //在2个临界状态之间的就为出现在视野中的
return true;
}
return false;
}
function isLoaded($img) {
return $img.attr('data-src') === $img.attr('src'); //如果data-src和src相等那么就是已经加载过了
}
function loadImg($img) {
$img.attr('src', $img.attr('data-src')); // 加载就是把自定义属性中存放的真实的src地址赋给src属性
}
script>
body>
总结:懒加载是一种独特而又强大的数据获取方法,它能够在用户滚动页面的时候自动获取更多的数据,而新得到的数据不会影响原有数据的显示,同时最大程度上减少服务器端的资源耗用。