创建 Js图片上传实现方法总结

图片上传是前端开发过程最常碰见的功能之一。现在有很多成熟的图片上传插件uploadify、file upload、 webuploader 等,除了这些HMTL5技术上也支持了这一需求,今天我们就来聊一聊这些是怎么实现的。以及根据他的原理自己写一个上传的功能。

一、uploadify插件

uploadify是一款免费的jquery的上传插件,有flash版本和html5版本,html5版本支持鼠标拖拽上传,因为一些HTML5版的一些兼容性,以flash版本使用居多,所以下面介绍flash版本的实现

     1)html代码

<link rel="stylesheet" type="text/css" href="/uploadify/uploadify.css">
<script src="/uploadify/jquery.min.js" type="text/javascript"></script>
<script src="/uploadify/jquery.uploadify.min.js" type="text/javascript"></script>
<form>
    <input type="file" name="file_upload" id="file_upload" />
</form>  

     2)JS代码

$(function(){
    $("#file_upload").uploadify({
        'auto':true,        //是否为自动上传
        'swf':'/uploadify/uploadify.swf',     //上传的flash插件
        'uploader':'/uploadify/uploadify.php',     //后台处理上传文件的脚本
        'buttonImage' :'/uploadify/browser.btn.png',      //上传按钮的外观为自定义图片
        'buttonText':'上传图片',      //上传按钮的文字信息
        'debug':true,       //开启uploadify的调试模式
        'fileObjName':'myFile',      //服务器端接收的对象,如$_POST['myFile']
        'fileSizeLimit':'5MB',      //上传文件的最大值
        'fileTypeDesc':'支持的格式:',                                   //可选择文件类型说明 
        'fileTypeExts':'*.jpg;*.png;*.bmp;*.gif',     //允许的文件扩展名
        'formData':{'somekey':'somevalue','someotherkey':1},  //上传文件时上传需要的表单值
        'height':'50px',                                                                      //按钮的高度
        'width':'100px',                                                                     //按钮的宽度
        'method':'post',                                                                    //上传的方式,默认为post
        'multi':true,                                                                           //允许批量上传,默认为true
        'preventCaching':true,                                                       //是否阻止缓存
        'progressData':'percentage',                                            //上传队列显示为速度还是百分比
        'onDialogOpen':function(){ alert('ok');}                           //打开上传按钮浏览框时触发事件
        'onUploadStart':function(){ }                                             //文件开始上传时触发事件
        'onUploadSuccess':function(file,data,response){        //文件上传成功时触发事件
        //成功以后这里继续操作
        },
                                                                                
      'onFallback':function(){                                                      //检测FLASH失败调用    
             alert("请安装FLASH控件后再试。");    
      },  
      //正在上传。。  
        'onSelect': function(file){  
           $("#alertDiv").text("正在上传...");  
            $("#alertDiv").show();  
        }, 
        'onSelectError':function(file, errorCode, errorMsg){    
            switch(errorCode) {    
               case -100:    
                  alert("上传的文件数量已经超出系统限制的"+$('#file_upload').uploadify('settings','queueSizeLimit')+"个文件!");    
                   break;    
               case -110:    
                   alert("文件 ["+file.name+"] 大小超出系统限制的"+$('#file_upload').uploadify('settings','fileSizeLimit')+"大小!");    
                          break;    
               case -120:    
                   alert("文件 ["+file.name+"] 大小异常!");    
                   break;    
               case -130:    
                   alert("文件 ["+file.name+"] 类型不正确!");    
                   break;    
            }    
        },  
        //所有文件处理完成时
        'onQueueComplete': function(queueData){ 
            alert(queueData.uploadsSuccessful);  
        }   


    });
});

   3)PHP后代的代码

public function uploadify(){
    if(!empty($_FILES){
        import('ORG.Net.UploadFile');
        $name = time().rand();
        $upload = new UploadFile();
        $upload->maxSize = 3145728;
        $upload->allowExts = array('jpg','gif','png','jpeg');
        $upload->savePath = './Public/upload/';
        $upload->saveRule = $name;
        if(!$upload->upload()){
            echo $upload->getErrorMsg();
        }else{
            $info = $upload->getUploadFileInfo();
            echo $info[0]['svaename'];
        }
    }
}
    

  uploadify插件分HTML5版本和FLAS版本,在chorme等为了安全性考试的浏览器中访问时直接flash被屏弊掉,而在firfox等浏览器如果不默认安装flash,则该功能不能实现,所以我体验不太好。如果研用HTML5版的一些低版本不支持

二、jquery file upload插件 

     1)基本使用

      jQuery File Upload主要使用了XHR作为上传方式,并且利用了相当多的现代浏览器功能,所以可以实现诸如批量上传、超大文件上传、图片预览、拖拽上传、上传进度显示、跨域上传等功能。

     Query File Upload包含了一堆文件,最核心的部分必须包括以下文件:

       1.jQuery核心库                         建议使用jQuery 1.8以上版本
       2.jquery.ui.widget.js :           jQuery UI Widget
       3.jquery.iframe-transport.js : 扩展iframe数据传输
       4.jquery.fileupload.js :          jQuery File Upload核心类
       5. jquery.xdr-transport.js         在IE下应载入此文件解决跨域问题

      引入文件以后html如下:

       <input id="fileupload" type="file" name="files[]" data-url="server/php/" multiple>


       js代码如下:      

       $('#fileupload').fileupload();

    2)一些扩展

          这就完成了一个简单的上传设置。只不过这只是一个最简单的使用方式,它完全实现一些扩展如下:

         上传完成以后的操作:

$('#fileupload').fileupload({
  done: function (e, data) {
         //do something
  }
});       
        
        进度条的设置

$('#fileupload').fileupload('option', {
   progressall: function (e, data) {
       var progress = parseInt(data.loaded / data.total * 100, 10);
       console.log(progress + '%');
   }
});

       更多扩展可以查看官方网站API

  3)一些注意的坑  

     json数据传送响应

     由于采用XHR在传递数据,服务器端返回的通常是JSON格式的响应,但是IE会将这些JSON响应误认为是文件传输,然后直接弹出下载框询问是否需要下载。

      解决方法:

      是必须将相应的Http Head从 Content-Type: application/json更改为 Content-Type: text/plain 

        定制自己的UI困难

        因为官方特意给了一个UI上的设置,这里的东西不可局部更改,更改时导致UI混乱。因此得他细找出来功能点进行指定的UI覆盖才可以,具体细节这里不在详细讲述了 

三、webuploader插件

      webUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件,使用WebUploader还可以批量上传文件、支持缩略图等等众多参数选项可设置,以及多个事件方法可调用,你可以随心所欲的定制你要的上传组件。

     1)html代码

<!DOCTYPE html>
<html>
<head lang="en">
   <meta charset="UTF-8">
   <title>webuploader</title>
   <link rel="stylesheet" href="__PUBLIC__/webuploader/webuploader.css"/>
   <script src="__PUBLIC__/jquery.min.js"></script>
   <script src="__PUBLIC__/webuploader/webuploader.js"></script>
   <style>
       * { padding: 0;margin: 0;}
       .progress {position: absolute;top: 0;left: 0; width: 100px;height: 15px; font-size: 12px; color: #fff; text-align: center; line-height: 15px;}
       .uploader-list .file-item {position: relative;}
       .progress span {display: inline-block; height: 100%; background: #1C9F09;}
   </style>
</head>
<body>
<div id="uploader-demo"> 
   <div id="fileList" class="uploader-list"></div>
   <div id="filePicker">选择图片</div>
</div>
</body>
</html>

     2)js代码

 <script>
    // 图片上传demo
    jQuery(function() {
        var $ = jQuery,
        $list = $('#fileList'),
        // 优化retina, 在retina下这个值是2
        ratio = window.devicePixelRatio || 1,
        // 缩略图大小
        thumbnailWidth = 100 * ratio,
        thumbnailHeight = 100 * ratio,
        // Web Uploader实例
        uploader;
        // 初始化Web Uploader
        uploader = WebUploader.create({
               // 自动上传。
              auto: true,
              // swf文件路径
              swf: '__PUBLIC__/webuploader/Uploader.swf',
              // 文件接收服务端。
              server: '__CONTROLLER__/webuploader',
              // 选择文件的按钮。可选。
               // 内部根据当前运行是创建,可能是input元素,也可能是flash.
               pick: '#filePicker',
               // 只允许选择文件,可选。
              accept: {
                   title: 'Images',
                   extensions: 'gif,jpg,jpeg,bmp,png',
                   mimeTypes: 'image/*'
              }
         });
        // 当有文件添加进来的时候
        uploader.on( 'fileQueued', function( file ) {
            var $li = $(
                '<div id="' + file.id + '" class="file-item thumbnail">' +
                '<img>' +
                '<div class="info">' + file.name + '</div>' +
                '</div>'
            ),
            $img = $li.find('img');
            $list.append( $li );
            // 创建缩略图
            uploader.makeThumb( file, function( error, src ) {
                if ( error ) {
                    $img.replaceWith('<span>不能预览</span>');
                    return;
                }
                $img.attr( 'src', src );
            }, thumbnailWidth, thumbnailHeight );
        });
        // 文件上传过程中创建进度条实时显示。
        uploader.on( 'uploadProgress', function( file, percentage ) {
            var $li = $( '#'+file.id ),
                $percent = $li.find('.progress span');
            // 避免重复创建
            if ( !$percent.length ) {
                $percent = $('<p class="progress"><span></span></p>')
                    .appendTo( $li )
                    .find('span');
            }
            $percent.css( 'width', percentage * 100 + '%').text(percentage * 100+'%');
        });

        // 文件上传成功,给item添加成功class, 用样式标记上传成功。
        uploader.on( 'uploadSuccess', function( file ) {
            console.log(file);
            $( '#'+file.id ).addClass('upload-state-done');
        });
        // 文件上传失败,现实上传出错。
        uploader.on( 'uploadError', function( file ) {
               var $li = $( '#'+file.id ),
                $error = $li.find('div.error');
               // 避免重复创建
              if ( !$error.length ) {
                  $error = $('<div class="error"></div>').appendTo( $li );
              }
              $error.text('上传失败');
        });
        // 完成上传完了,成功或者失败,先删除进度条。
        uploader.on( 'uploadComplete', function( file ) {
        });
    });
</script>

     3)php代码

     public function webuploader() {
   $upload = new \Think\Upload();                                 // 实例化上传类
   $upload->maxSize   =  3145728 ;                              // 设置附件上传大小
   $upload->exts      =  array('jpg', 'gif', 'png', 'jpeg');    // 设置附件上传类型
   $upload->rootPath  =  './Public/Uploads/';                // 设置附件上传根目录
   $upload->savePath  =  '';                                             // 设置附件上传(子)目录
   $upload->autoSub =    false;                                      // 关闭子目录
   // 上传文件
   $info   =   $upload->upload();
     if(!$info) {                                                                        // 上传错误提示错误信息
              $this->error($upload->getError());
   }else{                                                                                // 上传成功 获取上传文件信息
            $pathArr = array();
             foreach($info as $file){
                    array_push($pathArr, "Public/Uploads/".$file['savepath'].$file['savename']);
           }
            echo json_encode($pathArr);
   }
}

    webUploader是html5和flash两者做了兼容,对高低版本都做了一些良好的支持,而且官网API写的详细,实例很多,容易实用。在这么多插件中主动推荐使用这个插件

四、HMTL5怎么实现

这里提到了html5所以你懂的,这个不要考虑PC端了。一般都是手机端实现图片上传才会用HMTL5实现,具体实现方法如下:

        实现HMTL5图片上传肯定要用到FileReader来读取本地文件,FileReade的属性和方法如下:

属性,所有属性都是只读的:
FileReader.error,读取文件时,出现的DOMError。
FileReader.readyState,读取状态;0,没有数据加载;1,数据正在加载;2,读取已经完成。
FileReader.result,文件内容;该属性只在读取操作完成后才有效,并且格式取决于读取时使用的方法。
事件:
FileReader.onabort,读取操作中止。
FileReader.onerror,读取出现错误。
FileReader.onload,读取成功完成后。
FileReader.onloadstart,读取开始。
FileReader.onloadend,读取完成,无论是否读取成功。
FileReader.onprogress,当读取Blob内容时。
方法:
FileReader.abort() 中止读取。然后readyState变为2。
FileReader.readAsArrayBuffer() 将文件读取成ArrayBuffer。
FileReader.readAsBinaryString() 读取成二进制字符串。
FileReader.readAsDataURL() 读取成DataURL。
FileReader.readAsText() 读取成文本。

 预览功能实现:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图片上传预览</title>
<script type="text/javascript">
   function imgPreview(fileDom){
       //判断是否支持FileReader
       if (window.FileReader) {
           var reader = new FileReader();
       } else {
           alert("您的设备不支持图片预览功能,如需该功能请升级您的设备!");
       }
       //获取文件
       var file = fileDom.files[0];
       var imageType = /^image\//;
       //是否是图片
       if (!imageType.test(file.type)) {
           alert("请选择图片!");
           return;
       }
       //读取完成
       reader.onload = function(e) {
           //获取图片dom
           var img = document.getElementById("preview");
           //图片路径设置为读取的图片
           img.src = e.target.result;
       };
       reader.readAsDataURL(file);
   }
</script>
</head>
<body>
   <img id="preview" />
   <br />
   <input type="file" name="file" οnchange="imgPreview(this)" />
</body>
</html>

 预览功能实现:

function upload() {
   var xhr = new XMLHttpRequest();
   var progress = document.getElementById("progress")
   progress.style.display = "block";


   xhr.upload.addEventListener("progress", function(e) {
       if (e.lengthComputable) {
           var percentage = Math.round((e.loaded * 100) / e.total);
           progress.value = percentage;
       }
   }, false);


   xhr.upload.addEventListener("load", function(e){
         console.log("上传结束...")
     }, false);


   xhr.open("POST", "upload");
   xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
   xhr.onreadystatechange = function() {
       if (xhr.readyState == 4 && xhr.status == 200) {
           alert(xhr.responseText); // handle response.
           progress.style.display = "none";
           progress.value = 0;
       }
   };
   var file = document.getElementById("imgFile");
   var fd = new FormData();
   fd.append(file.files[0].name, file.files[0]);
   xhr.send(fd);
}

  

五、分析下原理自已动手写一个

上面我们基本总结了图片上传的经常用的插件及HTML5实现的方式。每个都有优点和缺点,一般为了兼容低版本都是走的flash,一旦走的是flash就会出现安装插件的请求,这个体验不好,在一上次做需求的时候需要用到多图片上传,索性自己写了个。

      实现原理:

      通过Iframe+form的结合。设置input file enctype="multipart/form-data" target="ajaxUpload" 属性允许选择多张图片上传,模拟input file上传功能安钮,当input file change的时候 通过form action把当前的图片上传给后台,后台设置,当前端iframe加载完成时获取server端返回的生成服务器上的img URL。解析数据生成远程的img.程现到页面上出来。然后做删除滚动一系列的后续工作等。

      Html代码:



<div class="scrollBox">
    <ul>
        <div id="shen-from">
        <iframe name="ajaxUpload" id="iframebox"></iframe>
            <form id="fileForm" name="fileForm" action="/post/addpictures" method="post" enctype="multipart/form-data" target="ajaxUpload">
               <input type="file" id="fileName" name="photos[]" multiple= "multiple" />
               <img class="addBtn" src="<%=baseImgPath%>dp/shen-add1.png" />
               <span id="returnMsg">正在上传...</span>
               <span id="data_text"></span>
            </form>
        </div>
    </ul>
</div>

     JS代码:

var ShensuFn=function(remote){

     this.attr= {
    '_shenText'   : $('._shenText'),    
    '_shenSelect' : $('._shenSelect'),
    '_shenfile'   : $('#fileName'),
    '_shenMsg'    : $('#returnMsg'),
    '_sheniframe' : $('#iframebox'),
    '_shenBox'    : $('.scrollBox'),
    '_shenUrl'    : $('.scrollBox ul'),
    '_shenDaText' : $('#data_text')
     };

   /*上传图片相关逻辑*/
imgUpload:function(){
//当选择当前文件时提交
var lName;
var that=this;
this.attr._shenfile.on('change',function(){
//没有选择图片时
var filVal  = $(this).val();

if(filVal==''){
return;
}
// 提示信息
   that.attr._shenMsg.show();  

   $("#fileForm").submit();
   that.attr._shenfile.val('');
})
//提交加载完成Iframe时设置图片


  this.attr._sheniframe.on('load',function(){
       //取出iframe中的数据
       var body = $(window.frames['ajaxUpload'].document.body); 
       var aLiLeng = that.attr._shenUrl.children().not("#shen-from").length;
       that.attr._shenDaText.text(body.context.textContent);  
       var _data=JSON.parse(that.attr._shenDaText.text());
var res=_data.data;

//如果数据为空或者不存在
   if((!res && _data.error!='-1') || (res.length<1 && _data.error!='-1')){                   
  return;  
  }
  //有错误信息时提示
  if(_data.error=='-1'){   
  alert(_data.errormsg);
  }
  //图片总数量超过9张时
  if((aLiLeng+res.length)>9){
  alert('你上传的图片张数过多,已为您添加前9张图片')
  //删除多余图片数
  res.splice(9-aLiLeng); 
  $("#fileForm").hide();
  //图片总数量等于9张时
  }else if((aLiLeng+res.length)==9){
  $("#fileForm").hide();
  }
  //隐藏数据
  that.attr._shenDaText.hide();
  //生成img
  for(var i=0;i<res.length;i++){
 
  $("<li><a class='big-photo2' rel='_shengroup' href="+res[i].url+"><img  class='showImg photo' alt='' _width="+res[i].width+"  _height="+res[i].height+" src="+res[i].minurl+" /></a><span class='close-btn'></span></li>").insertBefore($('#shen-from')); 
 
  var aLiLeng = that.attr._shenUrl.children().not("#shen-from").length;
  //UL的宽度
  that.attr._shenUrl.css('width',((aLiLeng+1)*(118+15))+'px');  
 
  //UL的scrollLeft
aLiLeng>2?(that.attr._shenBox.scrollLeft((aLiLeng-2)*(118+15))):(that.attr._shenBox.scrollLeft(0));

  //loading隐藏
  that.attr._shenMsg.hide();

  //关闭当前的图片并删除
  that.attr._shenUrl.find('.close-btn').click(function(){
$(this).parent().remove();
var aLiLeng = that.attr._shenUrl.children().not("#shen-from").length; 
//删除后计算UL的宽度
  that.attr._shenUrl.css('width',((aLiLeng+1)*(118+15))+'px');
  //删除后计算UL的left
aLiLeng>2?that.attr._shenBox.scrollLeft((aLiLeng-2)*(118+15)):that.attr._shenBox.scrollLeft(0);
//删除时检测当前的图片个数控制是否显示上传安钮 
   
  if(aLiLeng<9){
 
  $("#fileForm").show();
  }
  });
 
})
 }

 new ShensuFn();

总结:如上所述,总结所有目前图片上传的方法。及自己手动写的方式等,其中插件推荐使用webUploader,做了HMTL5 和FLASH的兼容处理。下面手动写的iframe的方式也是一种很好的实现方法,用它实现了局部刷新的功能。因为iframe加载整个页面不会刷新,而且避免再次出现了flash这个东西让用户安装的不好的体验方式,唯一要求的就是后台的一些配合,不过做开发需要后台的配合这个也合乎常理。



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值