• 搞清Image加载事件(onload)、加载状态(complete)后,实现图片的本地预览,并自适应于父元素内(完成)


    onload与complete介绍

    complete只是HTMLImageElement对象的一个属性,可以判断图片加载完成,不管图片是不是有缓存;而onload则是这个Image对象的load事件回调,当图片加载完成后执行onload绑定的函数。

    给下面一个例子,解释下:

    document.getElementById('load').onclick = function() {  
        var img = new Image();  
        img.src="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="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:0;
        left:0;
        filter:alpha(opacity=0); 
        opacity: 0;
    }

    静态页面的效果如图所示:

    梳理一下思路,我们要实现图片的本地预览,需要如下几点:
    1.点击file上传文件按钮后,选中图片后,获得图片的路径。
    2.根据图片实例一个new Image()得到图片的实际的大小。
    3.得到图片的实际大小,再根据显示区域的宽高来处理图片的宽高,让其自适应于父元素区域中。
    4.在IE9以及低版本浏览器中需要使用滤镜来实现图片的预览。

    根据以上几点我们就写如下代码,首先我们先创建一个构造函数。

    function DealPic(width,height){
        this.oriWidth = width;
        this.oriHeight = height;
    }

    这个oriWidthoriHeight指的是父区域的宽高,也就是图片要跟该宽高进行比较的值。

    接下来实现一个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';
            });    
        }   
    }  

    最后本地预览的效果如图所示:

  • 相关阅读:
    安装虚拟机及学习linux系统 20155222卢梓杰
    技能获取与编程学习 卢梓杰20155222
    人生第一篇博客
    20155228 2016-2017-2 《Java程序设计》第1周学习总结
    20155228 基于VirtualBox安装Ubuntu和学习linux命令的学习经历和心得
    20155228 获取技能的成功经验和关于C语言学习的调查
    20155228 你期望的师生关系是什么?
    预备作业03:安装虚拟机
    足球运动训练心得及经验分析-c语言学习调查
    我期望的师生关系
  • 原文地址:https://www.cnblogs.com/moqiutao/p/7283129.html
Copyright © 2020-2023  润新知