Track Image Loading效果代码分析


Posted in Javascript onAugust 13, 2007

目的
在图片的加载过程中,提供定义图片加载成功或加载失败/超时时的回调函数,并确保执行。 

动机
原生JavaScript已经对 Image 对象提供了 onload 和 onerror 注册事件。但在浏览器缓存及其他因素的影响下,用户在使用回退按钮或者刷新页面时 onload 事件常常未能稳定触发。在我开发的相册系统中,我希望图片能根据自定义的大小显示以免导致页面变形,例如最宽不得超过500px,而小于500px宽度的图片则按原大小显示。CSS2 提供了 max-width 属性能够帮组我们实现这一目的。但很遗憾,挨千刀的IE6并不支持。 

IE6一个弥补的办法就是通过注册 img.onload 事件,待图片加载完成后自动调整大小。以下代码取自著名的Discuz!论坛系统4.1版本对显示图片的处理。 

<img src="http://img8.imagepile.net/img8/47104p155.jpg" border="0"
onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; 
this.alt='Click here to open new windownCTRL+Mouse wheel to zoom in/out';}" 
onmouseover="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new windownCTRL+Mouse wheel to zoom in/out';}" 
onclick="if(!this.resized) {return true;} else {window.open('http://img8.imagepile.net/img8/47104p155.jpg');}" 
onmousewheel="return imgzoom(this);">

前文已述,浏览器并不保证事件处理函数执行。所以需要一个更稳定的方式跟踪图片加载过程,并执行设定的回调函数。 

实现
image.complete 属性标示的是图片加载状态,其值如果为ture,则表示加载成功。图片不存在或加载超时则值为false。利用 setInterval() 函数定时检查该状态则可以实现跟踪图片加载的状况。代码片断如下: 

ImageLoader = Class.create();
ImageLoader.prototype = {
  initialize : function(options) {
    this.options = Object.extend({
      timeout: 60, //60s
      onInit: Prototype.emptyFunction,
      onLoad: Prototype.emptyFunction,
      onError: Prototype.emptyFunction
    }, options || {});
    this.images = [];
    this.pe = new PeriodicalExecuter(this._load.bind(this), 0.02);
  },
       ........
}

利用Prototype 的PeriodicalExecuter类创建一个定时器,每隔20毫秒检查一次图片的加载情况,并根据状态执行 options 参数中定义的回调函数。 

使用

var loader = new ImageLoader({
  timeout: 30,
  onInit: function(img) {
    img.style.width = '100px';
  },
  onLoad: function(img) {
    img.style.width = '';
    if (img.width > 500) 
      img.style.width = '500px';
  },
  onError: function(img) {
    img.src = 'error.jpg'; //hint image
  }
});loader.loadImage(document.getElementsByTagName('img'));

上面的代码定义图片最初以100px显示,加载成功后如果图片实际宽度超过500px,则再强制定义为500px,否则显示原大小。如果图片不存在或加载超时(30秒为超时),则显示错误图片。 

同理,可以应用 ImageLoader 的回调函数来根据需求自定义效果,例如默认显示loading,加载完成后再显示原图;图片首先灰度显示,加载完成后再恢复亮度等等。例如: 

//need scriptaculous effects.js
var loader = new ImageLoader({
  onInit: function(img) {
    Element.setOpacity(img, 0.5); //默认5级透明
  },
  onLoad: function(img) {
    Effect.Appear(img);  //恢复原图显示
  }
});

附示例中包含完整的代码及使用pconline图片为例的测试, 注意 范例中使用了最新的Prototype 1.5.0_rc1。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 //EN">
<html>
<head>
<script src="prototype1.5.0_rc1.js"></script>
<script src="validation1.5.3/effects.js"></script>
</head>

<body>
<img id="img0" src="http://img.pconline.com.cn/images/photoblog/2026024/20069/14/1158169144171.jpg" />

<img id="img1" src="http://img.pconline.com.cn/images/photoblog/2026024/20069/14/1158169158366.jpg" />

<img id="img2" src="http://img.pconline.com.cn/images/photoblog/2026024/20069/14/1158169169983_mthumb.jpg" />

<br />加载失败测试<br />
<img id="img2" src="http://img.pconline.com.cn/images/photoblog/2026024/20069/14/000000000000.jpg" />

<script type="text/javascript">
ImageLoader = Class.create();
ImageLoader.prototype = {

  initialize : function(options) {
    this.options = Object.extend({
      timeout: 60, //60s
      onInit: Prototype.emptyFunction,
      onLoad: Prototype.emptyFunction,
      onError: Prototype.emptyFunction
    }, options || {});
    this.images = [];
    this.pe = new PeriodicalExecuter(this._load.bind(this), 0.02);
  },

  loadImage : function() {
    var self = this;
    $A(arguments).each(function(img) {
      if (typeof(img) == 'object')
        $A(img).each(self._addImage.bind(self));
      else
        self._addImage(img);
    });
  },

  _addImage : function(img) {
    img = $(img);
    img.onerror = this._onerror.bind(this, img);
    this.options.onInit.call(this, img);
    if (this.options.timeout > 0) {
      setTimeout(this._ontimeout.bind(this, img), this.options.timeout*1000);
    }
    this.images.push(img);
    if (!this.pe.timer)
      this.pe.registerCallback();
  },

    
  _load: function() {
    this.images = this.images.select(this._onload.bind(this));
    if (this.images.length == 0) {
      this.pe.stop();
    }
  },

  _checkComplete : function(img) {
    if (img._error) {
      return true;
    } else {
      return img.complete;
    }
  },

  _onload : function(img) {
    if (this._checkComplete(img)) {
      this.options.onLoad.call(this, img);
      img.onerror = null;
      if (img._error)
        try {delete img._error}catch(e){}
      return false;
    }
    return true;
  },

  _onerror : function(img) {
    img._error = true;
    img.onerror = null;
    this.options.onError.call(this, img);
  },

  _ontimeout : function(img) {
    if (!this._checkComplete(img)) {
      this._onerror(img);
    }
  }

}

var loader = new ImageLoader({
  timeout: 30,
  onInit: function(img) {
    img.style.width = '100px';
  },
  onLoad: function(img) {
    img.style.width = '';
    if (img.width > 500) { 
      img.style.width = '500px';
    }
  },
  onError: function(img) {
    img.src = 'http://img.pconline.com.cn/nopic.gif';
  }
});

loader.loadImage(document.getElementsByTagName('img'));

/*
var loader = new ImageLoader({
  timeout: 30,
  onInit: function(img) {
    Element.setOpacity(img, 0.5);
  },
  onLoad: function(img) {
    Effect.Appear(img);
  },
  onError: function(img) {
    img.src = 'http://img.pconline.com.cn/nopic.gif';
  }
});
*/

/*
$A(document.getElementsByTagName('img')).each(
function(img) {
  img.onload = function() {
    img.style.width = '300px';
  }
}
);
*/

</script>
</body>
</html>

Javascript 相关文章推荐
JSQL 批量图片切换的实现代码
May 05 Javascript
jQuery 验证插件 Web前端设计模式(asp.net)
Oct 17 Javascript
jQuery 绑定事件到动态创建的元素上的方法实例
Aug 18 Javascript
jquery validate添加自定义验证规则(验证邮箱 邮政编码)
Dec 04 Javascript
js的hasownproperty使用示例
Mar 02 Javascript
jQuery如何获取同一个类标签的所有值(默认无法获取)
Sep 25 Javascript
javascript实现checkBox的全选,反选与赋值
Mar 12 Javascript
微信小程序 下拉列表的实现实例代码
Mar 08 Javascript
JavaScript中this的用法及this在不同应用场景的作用解析
Apr 13 Javascript
利用ES6实现单例模式及其应用详解
Dec 09 Javascript
antd Upload 文件上传的示例代码
Dec 14 Javascript
tsconfig.json配置详解
May 17 Javascript
不错的JS中变量相关的细节分析
Aug 13 #Javascript
javascript-TreeView父子联动效果保持节点状态一致
Aug 12 #Javascript
TopList标签和JavaScript结合两例
Aug 12 #Javascript
Javascript-Mozilla和IE中的一个函数直接量的问题分析
Aug 12 #Javascript
IE和Mozilla的兼容性汇总event
Aug 12 #Javascript
收藏Javascript中常用的55个经典技巧
Aug 12 #Javascript
JavaScript-世界上误解最深的语言分析
Aug 12 #Javascript
You might like
PHP array_flip() 删除重复数组元素专用函数
2010/05/16 PHP
PHP备份/还原MySQL数据库的代码
2011/01/06 PHP
PHP 图片水印类代码
2012/08/27 PHP
php获取网页请求状态程序示例
2014/06/17 PHP
php和editplus正则表达式去除空白行
2015/04/17 PHP
ThinkPHP 框架实现的读取excel导入数据库操作示例
2020/04/14 PHP
14款NodeJS Web框架推荐
2014/07/11 NodeJs
Javascript基础教程之for循环
2015/01/18 Javascript
JavaScript自定义等待wait函数实例分析
2015/03/23 Javascript
jQuery简单动画变换效果实例分析
2016/07/04 Javascript
JS中数组重排序方法
2016/11/11 Javascript
简单理解js的冒泡排序
2016/12/19 Javascript
AngularJS使用带属性值的ng-app指令实现自定义模块自动加载的方法
2017/01/04 Javascript
d3.js中冷门却实用的内置函数总结
2017/02/04 Javascript
js 作用域和变量详解
2017/02/16 Javascript
AngularJS创建一个上传照片的指令实例代码
2018/02/24 Javascript
node之本地服务器图片上传的方法示例
2019/03/26 Javascript
2019年度web前端面试题总结(主要为Vue面试题)
2020/01/12 Javascript
Vue打包部署到Nginx时,css样式不生效的解决方式
2020/08/03 Javascript
浅析Python中的多进程与多线程的使用
2015/04/07 Python
Python的包管理器pip更换软件源的方法详解
2016/06/20 Python
Python微信库:itchat的用法详解
2017/08/14 Python
python format 格式化输出方法
2018/07/16 Python
详解Python中is和==的区别
2019/03/21 Python
python主要用于哪些方向
2020/07/05 Python
怎么解决pycharm license Acti的方法
2020/10/28 Python
详解python中的三种命令行模块(sys.argv,argparse,click)
2020/12/15 Python
Lookfantastic澳大利亚官网:英国知名美妆购物网站
2021/01/07 全球购物
生物技术研究生自荐信
2013/11/12 职场文书
毕业生自荐信
2013/12/14 职场文书
优秀学生自我鉴定范例
2013/12/18 职场文书
关于工作经历的证明书
2014/10/11 职场文书
入党积极分子对十八届四中全会期盼的思想汇报
2014/10/17 职场文书
债务纠纷代理词
2015/05/25 职场文书
2016年清明节红领巾广播稿
2015/12/17 职场文书
Python FuzzyWuzzy实现模糊匹配
2022/04/28 Python