[toc]
## 作用
保证页面打开的速度
一般来说3s之内如果首页打不开就被称之为**死亡页面**了。
## 原理
>1)对于首屏内容中的图片:首先给对应的区域一张默认图片占着位置(默认图需要灰常小,一般可以维持在5kb以内),当首屏内容都加载完成后(或则也可以给一个延迟的时间),我们才开始加载真实的图片
>2)对于其它屏中的图片,也是给一张默认的图片占位,当滚动条滚动到对应区域的时候,我们再开始加载真实的图片
扩展:数据的异步加载,开始只把前两屏的数据加载绑定出来,后面的数据不进行处理,当页面滚动到对应区域的时候再重新请求数据然后绑定渲染数据。
## 实现
```
.banner {
//当图片还没加载时以默认图片显示
background:url() no-repeat center center #elelel;
}
.banner img{
display:none; //在开始的时候IMG的SRC属性没有地址,这样的话在IE浏览器中会显示一张碎图,不美观,所以我们让其默认是隐藏的,当真实图片加载完成后显示
width:100%;
height:100%;
}
```
```
<div class="banner" id="banner">
// trueImg是当前IMG标签的自定义属性,存储的是真实图片的地址
<img src="" trueImg="img/jd.jpg"/>
</div>
```
```
var banner = document.getElementById("banner"),imgFir = banner.getElemetsByTagName("img")[0];
//window.onload
window.setTimeout(function(){
imgFir.src = imgFir.getAttribute("trueImg");
imgFir.style.display = "block";
},500)
```
以上处理还是不完整的:如果我们获取的真实图片地址是错误的,当赋值给IMG的SRC属性的时候,不仅控制台会报错,而且页面中会出现碎图或则叉子图,影响用户体验
获取图片的地址,验证地址的有效性,是有效的才赋值,不是有效的不进行赋值处理
```
var oImg = document.createElement("img");
var oImg = new Image; //等同有上面,都是创建一个临时的IMG标签
oImg.src = imgFir.getAttribute("trueImg");
oImg.onload = function(){ //当图片能够正常加载
imgFir.src = this.src;
imgFir.style.display = "block";
oImg = null;
}
```
## 单张图片加载
![](https://box.kancloud.cn/0c1905e8fee3c0e966117a7cd6f5745f_585x329.png)
```
window.onscroll = function(){
var A = banner.offsetHeight + banner.offsetTop;
}
```
![](https://box.kancloud.cn/60a8246bbb9dfb71b6cbe38239c79bc9_841x352.png)
这样有个问题会被加载多次
为已加载的图片做一个标识
![](https://box.kancloud.cn/00e05b0535c2a624ea4d93bb2e7c42f5_624x349.png)
这样仍然有问题的是,若图片不存在,随着滚动,会反复执行事件函数(进不到.onload)中,
So应该把`isLoad`的设置放在`onload`外
![](https://box.kancloud.cn/db4d303b5b23e9d1f167b96674f7269b_823x233.png)
## 多张图片加载
1、 ajax异步获取
2、 字符串拼接,将数据和模板绑定
3、 循环判断并加载
```
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<!--移动端就这样放这-->
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"/>
<style>
*{ margin: 0; padding: 0; }
ul{ list-style: none; padding: 10px; }
ul li{ position: relative; height: 60px; padding: 10px; border-bottom: 1px dashed #ccc; }
ul li>div:nth-child(1){
position: absolute;
left: 0;
top: 10px;
width: 60px;
height: 60px;
background: url("images/default.jpg") no-repeat center;
background-size: cover; /*覆盖*/
}
ul li>div:nth-child(1) img{
display: none;
width: 100%;
height: 100%;
opacity: 0;
filter: alpha(opacity=0);
}
ul li>div:last-child{
padding: 5px;
box-sizing: border-box;
overflow: hidden;
height: 60px;
_background: lightblue;
margin-left: 70px;
}
ul li>div:last-child h2{
line-height: 20px;
font-size: 14px;
/*标题省略号*/
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
ul li>div:last-child p{
font-size: 12px;
color: #999;
}
</style>
</head>
<body>
<ul id="newsList">
<li>
<div><img src="" alt=""/></div>
<div>
<h2>标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题标题</h2>
<p>描述描述描述描述描述描述描述描述描述描述描述</p>
</div>
</li>
<!--<li></li>
<li></li>
<li></li>
<li></li>-->
</ul>
</body>
</html>
<script src="utils.js"></script>
<script>
/*获取数据*/
//ajax
var jsonData = null; //这会还没有数据
var oUl = document.getElementById('newsList');
var imgList = oUl.getElementsByTagName('img'); //数据还没做呢
~function (){
var xhr = new XMLHttpRequest();
xhr.open('get','jsonData.txt?_'+Math.random(),false); //同步获取 可以避免浏览器的缓存问题,上一次获取来的数据,如果下一次地址没变我默认从本地缓存读取。不在去服务器去请求了 url ? 问号后面的是参数集合 集合和集合用&符号分开 ?set=1 &weight=80
xhr.onreadystatechange = function (){
if(xhr.readyState == 4 && xhr.status == 200){ // reg = /^2\d{2}$/ 304 开头代表你从本地缓存读取过来的 404 5开头代表服务端错误
//jsonData = xhr.responseText; //
jsonData = utils.jsonParse(xhr.responseText); //把文本转化为json格式的对象
}
}
xhr.send(null); //发送
}();
console.log(jsonData); //成功获取到数据
//数据绑定,把json中的数据,我们这次用字符串拼接的方式动态绑定
~function (){
if(jsonData){ //首先判断我们数据已经成功获取
//循环拼接ul里面的字符串
var str = '';
for(var i=0; i<jsonData.length; i++){
var cur = jsonData[i];
str += '<li>';
str += '<div><img src="" trueSrc="' + cur.img + '" /></div>';
str += '<div><h2>'+ cur.title +'</h2><p>'+ cur.desc+'</p></div>';
str += '</li>';
}
oUl.innerHTML = str; //把拼接好的字符串赋值给列表的innerHTML
}
}();
//图片延迟加载 首先先实现单张图片延迟加载
function imgDelayLoad(curImg){ //??这个函数要被用多少次,jsonData.length
//
if(curImg.isLoad){
return;
}
var tempImg = new Image();
tempImg.src = curImg.getAttribute('trueSrc'); //临时的图片就去加载真是的图片资源了
tempImg.onload = function (){
curImg.src = this.src; //说明已经加载成功了,我们这个图片的资源路径是有效的。
curImg.style.display = 'block';
tempImg = null;
}
curImg.isLoad = true; //只要你曾经加载过,不管是否成功我都没有必要去加载第二次了
}
//多张图片延迟加载
// 首先获取我们所有的图片集合
function allImgDelay(){
for(var i=0; i<imgList.length; i++){
//给每一个图片延迟加载
var curImg = imgList[i];
if (curImg.isLoad) continue; //优化 曾经加载过的图片就不需要再延迟加载了
var browerBottomDisBodyTop = utils.getWin('clientHeight') + utils.getWin('scrollTop'); //浏览器底部距离body顶端
var imgParentBottomDisBodyTop = utils.offset(curImg.parentNode).top + curImg.parentNode.offsetHeight; //图片父亲容器底部距离body顶端
if(browerBottomDisBodyTop>imgParentBottomDisBodyTop){ //判断这个图片是否已经出现在了浏览器的可视窗口内, 我们要判断img这个图片的parentNode
imgDelayLoad(curImg); //分别多次调用单个图片延迟加载
fadeIn(curImg); //淡入的方式
}
}
}
window.setTimeout(allImgDelay,1000); //第一屏图片延迟加载,第一屏已经完全出现在可视窗口内,所以就需要图片延迟加载
window.onscroll = allImgDelay; //滚轮的时候也需要图片延迟加载
//处理多张
function fadeIn(curImg){ //淡入
var duration = 1000; //这么长的时间间隔完成淡入效果
var target = 1; //淡入效果变化的透明度区间,从0运动到1
var interval = 10; //执行定时器的时间间隔
var step = (target/duration)*interval; //每一次执行定时器需要加上的步长
var timer = window.setInterval(function (){
if(curOpacity >= target){ //说明已经运动到了终点,停止定时器
window.clearInterval(timer);
//赋值终点的动作 把target的值赋值给当前元素的样式
return;
}
debugger;
var curOpacity = utils.getCss(curImg,'opacity'); //赋值之前需要先获取,因为要在当前的基础上去累加步长
curOpacity += step;
curImg.style.opacity = curOpacity; //把已经累加好的重新赋值给样式这样才能有每次淡入一点的效果
curImg.style.filter = 'alpha(opacity='+ curOpacity*100+ ')'; //兼容问题的处理
},interval);
}
</script>
```
- 空白目录
- window
- location
- history
- DOM
- 什么是DOM
- JS盒子模型
- 13个核心属性
- DOM优化
- 回流与重绘
- 未整理
- 文档碎片
- DOM映射机制
- DOM库封装
- 事件
- 功能组件
- table
- 图片延迟加载
- 跑马灯
- 回到顶部
- 选项卡
- 鼠标跟随
- 放大镜
- 搜索
- 多级菜单
- 拖拽
- 瀑布流
- 数据类型的核心操作原理
- 变量提升
- 闭包(scope)
- this
- 练习题
- 各种数据类型下的常用方法
- JSON
- 数组
- object
- oop
- 单例模式
- 高级单例模式
- JS中常用的内置类
- 基于面向对象创建数据值
- 原型和原型链
- 可枚举和不可枚举
- Object.create
- 继承的六种方式
- ES6下一代js标准
- babel
- 箭头函数
- 对象
- es6勉强笔记
- 流程控制
- switch
- Ajax
- eval和()括号表达式
- 异常信息捕获
- 逻辑与和或以及前后自增
- JS中的异步编程思想
- 上云
- 优化技巧
- 跨域与JSONP
- 其它跨域相关问题
- console
- HTML、XHTML、XML
- jQuery
- zepto
- 方法重写和方法重载
- 移动端
- 响应式布局开发基础
- 项目一:创意简历