搞清Image加载事件(onload)、加载状态(complete)后,实现图片的本地预览,并自适应于父元素内(完成)
onload与complete介绍
complete只是HTMLImageElement对象的一个属性,可以判断图片加载完成,不管图片是不是有缓存;而onload则是这个Image对象的load事件回调,当图片加载完成后执行onload绑定的函数。
给下面一个例子,解释下:
document.getElementById('load').onclick = function() {
var img = new Image();
img.src="data:images/avatar.png";
if(img.complete) {
console.log('dd');
}
img.onload = function() {
console.log('ff');
}
}
打印结果:
第一次点击,谷歌浏览器结果为:dd;IE浏览器结果为:ff。
第二次点击,谷歌浏览器结果为:dd,ff;IE浏览器结果为:ff。
第三次点击,谷歌浏览器结果为:dd,ff;IE浏览器结果为:dd,ff。
...
例2:
document.getElementById('load').onclick = function() {
var img = new Image();
if(img.complete) {
console.log('dd');
}
img.onload = function() {
console.log('ff')
}
img.src="data:images/avatar.png";
}
打印结果:
第一次点击,谷歌浏览器结果为:dd,ff;IE浏览器结果为:ff。
第二次点击,谷歌浏览器结果为:dd,ff;IE浏览器结果为:ff。
第二次点击,谷歌浏览器结果为:dd,ff;IE浏览器结果为:ff。
...
例3:
document.getElementById('load').onclick = function() {
var img = new Image();
if(img.complete) {
console.log('dd');
}
img.onload = function() {
console.log('ff')
}
img.src="";
}
打印结果:
第一次点击,谷歌浏览器结果为:dd;IE浏览器结果为:空。
第二次点击,谷歌浏览器结果为:dd;IE浏览器结果为:空。
第二次点击,谷歌浏览器结果为:dd;IE浏览器结果为:空。
...
根据结果得出:对于 complete 属性来讲,IE是根据图片是否显示过来判断,就是说当加载的图片显示出来后,complete 属性的值才为 true ,否则一直是 false ,和以前是否加载过该张图片没有关系,即和缓存没有关系!但是其它浏览器表现出来的确不一样,只要以前加载过该图,浏览器有缓存,也无论src是否有值,成功与否,只要获取到image,就可以执行,complete 就为 true。所以这个complete在不同浏览器中结果是不一样的。
本地图片预览
首先先写下布局,html代码:
<div class="centerView">
<div class="localPreview">
<img id="showViewImg"/>
</div>
<a class="inputParent" href="javascript:void(0)">
<i>点击上传文件</i>
<input type="file" id="filePath" onchange="getCurrFile()"/>
</a>
</div>
css代码:
.centerView{
width:150px;
}
.localPreview{
position:relative;
width:150px;
height:150px;
line-height:150px;
text-align:center;
background:#ccc;
}
.localPreview img{
position: relative;
vertical-align: middle;
}
.inputParent{
position:relative;
display:block;
margin:10px auto;
cursor:pointer;
width:80px;
height:30px;
line-height:30px;
background:#27bb6e;
text-align: center;
font-size:12px;
color:#fff;
}
.inputParent i{
font-style: normal;
color:#fff;
}
.inputParent #filePath{
position:absolute;
width:100%;
height:100%;
top:;
left:;
filter:alpha(opacity=0);
opacity:;
}
静态页面的效果如图所示:

梳理一下思路,我们要实现图片的本地预览,需要如下几点:
1.点击file上传文件按钮后,选中图片后,获得图片的路径。
2.根据图片实例一个new Image()得到图片的实际的大小。
3.得到图片的实际大小,再根据显示区域的宽高来处理图片的宽高,让其自适应于父元素区域中。
4.在IE9以及低版本浏览器中需要使用滤镜来实现图片的预览。
根据以上几点我们就写如下代码,首先我们先创建一个构造函数。
function DealPic(width,height){
this.oriWidth = width;
this.oriHeight = height;
}
这个oriWidth与oriHeight指的是父区域的宽高,也就是图片要跟该宽高进行比较的值。
接下来实现一个getObjectURL,干嘛的呢,如果支持file对象支持files,就返回只包含url的一个对象,如果是IE9以及低版本浏览器返回的对象中还包括滤镜图片的原始大小。
DealPic.prototype.getObjectURL = function(fileObj){
var result = {} ;
var file;
if(fileObj.files){
file = fileObj.files[0];
if (window.createObjectURL!=undefined) { // basic
result.url = window.createObjectURL(file) ;
}else if (window.URL!=undefined) { // mozilla(firefox)
result.url = window.URL.createObjectURL(file) ;
}else if (window.webkitURL!=undefined) { // webkit or chrome
result.url = window.webkitURL.createObjectURL(file) ;
}
}else{
var hiddenAlphaImageWidth,hiddenAlphaImageHeight;
var hiddenAlphaImage = document.createElement('img');
document.body.appendChild(hiddenAlphaImage);
fileObj.select();
fileObj.blur();
result.url = document.selection.createRange().text;
hiddenAlphaImage.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image)";
hiddenAlphaImage.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = result.url;
//但是当滤镜使用的图片超过10M大小,使用上面的代码页面会报错,说hiddenAlphaImage出现未指明的错误;
//解决办法就是使用下面的注释的方式,注释上面的两行代码
//使用下面代码滤镜图片超过10M后本地预览不了,通过这个滤镜得到的图片的宽高始终是28*30
//hiddenAlphaImage.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src=\"" + result.url + "\")";
result.width = hiddenAlphaImage.offsetWidth;
result.height = hiddenAlphaImage.offsetHeight;
if(hiddenAlphaImage.parentNode){
hiddenAlphaImage.parentNode.removeChild(hiddenAlphaImage);
}
}
return result;
}
在IE低版本浏览器为什么要这样处理呢,如果我们要得到滤镜图片的元素大小,首先得创建一个img元素,然后通过IE浏览器的document.selection.createRange().text得到图片路径,然后给这个img元素进行设置,这儿关键得用到filter的sizingMethod属性。
sizingMethod属性:可选值,设置或检索的方式来显示一个图像在对象边界显示方式。有三个值:
- crop:裁剪图像以适应对象的尺寸;
- image:默认值,扩大或减少对象的边界,以适应图像的尺寸;
- scale:伸展或收缩图像填充对象的边界;
这儿使用image才能得到滤镜图片的原始大小。然后返回。
如果一开始只是把这个url返回回去,没有返回滤镜图片的实际大小,就不能达到自适应的效果。
当然上面获取图片的url用到的是window.createObjectURL,也可以用FileReader.readAsDataURL读取指定Blob或File的内容。
简单实现一下:
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
var showImg = document.getElementById('showViewImg');
showImg.src = e.target.result;
showImg.style.width = '150px';
showImg.style.height = '80px';
};
reader.readAsDataURL(input.files[0]);
}
这儿就不详细介绍了,只是这儿得到的url是base64编码的字符串,所以我一般还是选中上面第一种方式。
接下来就是图片自适应的比较方法:
DealPic.prototype.getPicResult = function(targetWidth,targetHeight,callback){
if(this.oriWidth / this.oriHeight > targetWidth / targetHeight){
var th = this.oriHeight;
var tw = this.oriHeight / targetHeight * targetWidth;
}else{
var tw = this.oriWidth;
var th = this.oriWidth / targetWidth * targetHeight;
}
if(callback){
callback(tw,th);
}
}
这儿就不细说了。
最后就是绑定到file按钮上的change事件的方法了。
function getCurrFile(){
var fileObj = document.getElementById('filePath');
var showImgObj = document.getElementById('showViewImg');
var newPicObj = new DealPic(150,150);
var resultFileObj = newPicObj.getObjectURL(fileObj);
if(fileObj.files){
var newImg = new Image();
newImg.onload = function(){
newPicObj.getPicResult(newImg.width,newImg.height,function(tw,th){
showImgObj.style.width = tw + 'px';
showImgObj.style.height = th + 'px';
});
}
newImg.src = resultFileObj.url;
showImgObj.setAttribute('src',resultFileObj.url);
}else{
showImgObj.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";
showImgObj.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = resultFileObj.url;
//IE9低版本不设置图片src会显示裂图,所以设置一个透明图片或者base64的透明图片
showImgObj.setAttribute('src','./images/transparent.png');
//showImgObj.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
newPicObj.getPicResult(resultFileObj.width,resultFileObj.height,function(resw,resh){
showImgObj.style.width = resw + 'px';
showImgObj.style.height = resh + 'px';
});
}
}
最后的js代码总结:
function DealPic(width,height){
this.oriWidth = width;
this.oriHeight = height;
}
DealPic.prototype.getObjectURL = function(fileObj){
var result = {} ;
var file;
if(fileObj.files){
file = fileObj.files[0];
if (window.createObjectURL!=undefined) { // basic
result.url = window.createObjectURL(file) ;
}else if (window.URL!=undefined) { // mozilla(firefox)
result.url = window.URL.createObjectURL(file) ;
}else if (window.webkitURL!=undefined) { // webkit or chrome
result.url = window.webkitURL.createObjectURL(file) ;
}
}else{
var hiddenAlphaImageWidth,hiddenAlphaImageHeight;
var hiddenAlphaImage = document.createElement('img');
document.body.appendChild(hiddenAlphaImage);
fileObj.select();
fileObj.blur();
result.url = document.selection.createRange().text;
hiddenAlphaImage.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=image)";
hiddenAlphaImage.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = result.url;
//但是当滤镜使用的图片超过10M大小,使用上面的代码页面会报错,说hiddenAlphaImage出现未指明的错误;
//解决办法就是使用下面的注释的方式,注释上面的两行代码
//使用下面代码滤镜图片超过10M后本地预览不了,通过这个滤镜得到的图片的宽高始终是28*30
//hiddenAlphaImage.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src=\"" + result.url + "\")";
result.width = hiddenAlphaImage.offsetWidth;
result.height = hiddenAlphaImage.offsetHeight;
if(hiddenAlphaImage.parentNode){
hiddenAlphaImage.parentNode.removeChild(hiddenAlphaImage);
}
}
return result;
}
DealPic.prototype.getPicResult = function(targetWidth,targetHeight,callback){
if(this.oriWidth / this.oriHeight > targetWidth / targetHeight){
var th = this.oriHeight;
var tw = this.oriHeight / targetHeight * targetWidth;
}else{
var tw = this.oriWidth;
var th = this.oriWidth / targetWidth * targetHeight;
}
if(callback){
callback(tw,th);
}
}
function getCurrFile(){
var fileObj = document.getElementById('filePath');
var showImgObj = document.getElementById('showViewImg');
var newPicObj = new DealPic(150,150);
var resultFileObj = newPicObj.getObjectURL(fileObj);
if(fileObj.files){
var newImg = new Image();
newImg.onload = function(){
newPicObj.getPicResult(newImg.width,newImg.height,function(tw,th){
showImgObj.style.width = tw + 'px';
showImgObj.style.height = th + 'px';
});
}
newImg.src = resultFileObj.url;
showImgObj.setAttribute('src',resultFileObj.url);
}else{
showImgObj.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";
showImgObj.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = resultFileObj.url;
//IE9低版本不设置图片src会显示裂图,所以设置一个透明图片或者base64的透明图片
showImgObj.setAttribute('src','./images/transparent.png');
//showImgObj.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
newPicObj.getPicResult(resultFileObj.width,resultFileObj.height,function(resw,resh){
showImgObj.style.width = resw + 'px';
showImgObj.style.height = resh + 'px';
});
}
}
最后本地预览的效果如图所示:

搞清Image加载事件(onload)、加载状态(complete)后,实现图片的本地预览,并自适应于父元素内(完成)的更多相关文章
- image的加载事件(onload)和加载状态(complete)
之前做过这样一个需求,要让商家页的商家图片按照图片外面box的大小等比例缩放.之前的想法是在页面中先输出图片的src,然后在页面底部初始化js,然后在js中写相应的可以使图片按照box的大小等比例缩放 ...
- JS---BOM基本知识 (顶级对象,系统对话框,加载事件,location对象, history对象, navigator对象)
BOM JavaScript分三个部分: 1. ECMAScript标准---基本语法 2. DOM--->Document Object Model 文档对象模型,操作页面元素的 3. BOM ...
- 利用js加载本地图片预览功能
直接上代码: 经测试,除safari6包括6以下不支持,其他均可正常显示. 原因:safari6不支持filereader,同时不能使用IE滤镜导致失效. fix: 可以利用canvas,解决safa ...
- JS事件 加载事件(onload)注意:1. 加载页面时,触发onload事件,事件写在<body>标签内。 2. 此节的加载页面,可理解为打开一个新页面时。
加载事件(onload) 事件会在页面加载完成后,立即发生,同时执行被调用的程序. 注意:1. 加载页面时,触发onload事件,事件写在<body>标签内. 2. 此节的加载页面,可理解 ...
- jquery mobile在页面加载时添加加载中效果 document.ready 和window.onload执行顺序比较
想要添加这个效果,先来弄明白页面的加载和事件执行顺序,看这个简单例子: <html xmlns="http://www.w3.org/1999/xhtml"> < ...
- 深入理解DOM事件类型系列第六篇——加载事件
前面的话 提到加载事件,可能想到了window.onload,但实际上,加载事件是一大类事件,本文将详细介绍加载事件 load load事件是最常用的一个事件,当页面完全加载后(包括所有图像.java ...
- 从零开始学 Web 之 jQuery(一)jQuery的概念,页面加载事件
大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...
- 支持xhr浏览器:超时设定、加载事件、进度事件
各个浏览器虽然都支持xhr,但还是有些差异. 1.超时设定 IE8为xhr对象添加了一个timeout属性,表示请求在等待响应多少毫秒后就终止.再给timeout这只一个数值后,如果在规定的时间内浏览 ...
- js 动态加载事件的几种方法总结
本篇文章主要是对js 动态加载事件的几种方法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助 有些时候需要动态加载javascript事件的一些方法往往我们需要在 JS 中动态添 ...
随机推荐
- Python学习笔记【第六篇】:迭代器、生成器、高阶函数、装饰器
迭代器 迭代器是访问集合元素的一种方式,迭代器从对象的第一个元素开始访问,知道所有元素被访问完成.迭代器只能往前访问,不能通过索引访问. 类型内部使用__iter__()方法转为迭代器,使用__nex ...
- 二、activiti工作流-创建25张表
首先我们在eclipse上创建一个maven项目 然后在resources下面创建一个file,并命名问activiti.cfg.xml activiti.cfg.xml的配置内容如下 <?xm ...
- python读取pdf文件
pdfplumber简介 Pdfplumber是一个可以处理pdf格式信息的库.可以查找关于每个文本字符.矩阵.和行的详细信息,也可以对表格进行提取并进行可视化调试. 文档参考https://gith ...
- 推荐一篇关于java集合的博文,写的很nice
这也是我自己在网上看到的一篇博文,作者的博文都很棒,以后还会持续为大家推荐好的博文,只要大家不骂我只会转别人的博文,自己不会写,其实这些都是基础,前辈们已经在实践中总结的很细很全了,所以也没必要去总结 ...
- (转)[Python 网络编程] makefile (三)
socket.makefile(mode ='r',buffering = None,*,encoding = None,errors = None,newline = None )返回一个与套接字相 ...
- Redis主从+KeepAlived实现高可用
Redis是我们当下比较流行使用的非关系数据库,可支持多样化的数据类型,多线程高并发支持,redis运行在内存拥有更快的读写.因为redis的表现如此出色,如何能保障redis在运行中能够应对宕机故障 ...
- mysql 开发基础系列8 表的存储引擎
一. 表的存储引擎 1. 概述 插件式存储引擎是mysql数据库最重要的特性之一, 用户可以根据应用的需要选择如何存储和索引数据,是否使用事务等.在mysql 5.0里支持的引擎包括: MyISAM, ...
- socket编程(C++)
介绍 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 过程介绍 服务器端和客户端通信过程如下所示: 服务端 服务端的过程主要在该图的左侧部分,下 ...
- web进修之—Hibernate 懒加载(6)
关于懒加载 在关系数据库设计的时候,我们很多时候把表之间的关系设置为强关联(使用外键进行约束),在Hibernate中利用对象的包含关系进行维护(HIbernate本身就是面向对象的数据库操作模式), ...
- 比MySQL快6倍 深度解析国内首个云原生数据库POLARDB的“王者荣耀”
随着移动互联网.电子商务的高速发展,被使用最多的企业级开源数据系统MySQL面临着巨大挑战——为迎接“双11"的高并发要提前做好分库分表;用户不断激增要将读写分离才能应对每天上亿次的访问,但 ...