兼容IE低版本的文件上传解决方案

文件上传兼容简直头疼,为此特地封装了个方法,支持IE低版本(>=7)上传及现代浏览器显示上传进度,css

此方法只是个hello world,jser可根据本身的需求增减功能及样式html

敬上代码,抛砖引玉android

调用web

    var $file = $('input控件');
    var config = {
    fileExtension: 'jpg, png, pdf, psd',  //容许上传de文件格式
    fileSize: 100*1024*1024, //容许上传的最大尺寸
    uploadUrl: '***', //上传地址
    deleteUrl: '***', //删除地址
    uploadCb: function(res){
      console.log('success')
    },
    deleteCb: function(res){
      console.log('delete')
    }
  }
    $file.uploadFile(config)

方法ajax

(function($){
  // 全局变量
  var $this = '', //上传控件
      $container, //最外层容器
      $showFileContainer, //显示文件容器
      $showFileItem //显示单个文件
  var fileId = new Date().getTime(); //时间戳,区分每次上传
  var config = {};  // 配置参数
  // 关于上传进度变量
  var ot = 0; //上次调用的时间
  var oloaded = 0; //已上传文件大小
  var xhr = '';

  $.fn.uploadFile = function(conf){
    // 接收配置参数
    config = conf;
    $this = $(this);
    new initLayout($this)
    var inputData = [];
    /**
     * 上传文件
     * -----------
     * input files属性ie10及如下不支持
     * formdata ie10如下不支持
     * 根据是否支持files属性判断现代浏览器
     */
    $('body').on('change propertychange',$this,function(){
      fileId = new Date().getTime(); //更新时间戳
      // 区分ie10及如下
      if(browserInfo().browser.name == "Internet Explorer" && browserInfo().browser.edition*1 < 11){
        // ie低版本浏览器

        // ie单个文件过滤限制
        ie_singleFilefilter()
      }else{
        // 现代浏览器
        var files = $this[0].files;
        // files无数据跳出
        if(!files.length){
          return false
        }
        // 单个文件过滤限制
        new singleFilefilter(files)
        return false
      }
      // 最后执行
      clearFile();
    })

    // 删除单个文件
    $container.on('click',".f-itemDel",function(ev){
      if(!config.deleteUrl){
        return false
      }
      $.ajax({
        type: "POST",
        url: config.deleteUrl,
        data: {},
          success :function(data){
              var $del = $(ev.target);
              $del.closest('.f-item-info').remove();
              // 删除回调
              config.deleteCb(data);

              clearFile();
          },
          error: function(data){
            
          }
      });
    })
  }


  // 初始化布局
  function initLayout(){
    var inpId = $this.prop('id')?$this.prop('id'): (new Date).valueOf();
    var $creatParent = $('<div class="f-container">\
    <div class="f-input"></div>\
    <div class="f-preview"></div>\
    <div class="f-button"><label class="f-label-btn" for="'+inpId+'">add file</label></div>\
    <div class="f-showInfo"></div>\
    </div>');
    $this.after($creatParent);
    $creatParent.find('.f-label-btn').append($this);

    $container = $creatParent;
    $showFileContainer = $container.find(".f-showInfo")
  }

  /**
   * singleFilefilter 
   * 单个文件过滤-限制格式、大小、数量
   * -------
   * @param singleFile 
   * 接收单个文件
   * ---------
   * @return
   */
  function singleFilefilter(files){
    var singleFile = files[0]; //获取单个文件
    var extensions = config.fileExtension.split(','); //容许拓展名
    var singleExtension = '' ;// 单文件拓展名
    var singleSize = singleFile.size; //单文件大小
    var isNext = false;
    // 格式限制
    singleExtension = singleFile.name.substring(singleFile.name.lastIndexOf(".")+1).toLowerCase();
    if(extensions && extensions.length){
      for(var i = 0; i < extensions.length; i++){
        if(singleExtension == extensions[i].trim()){
          isNext = true;
        }
      }
    }
    // 判断isNext和singleExtension,为空或为false时提示
    if(!isNext){
      alert('文件格式不正确!');
      clearFile()
      return false;
    }
    // 大小限制
    if(singleSize > config.fileSize){
      alert("文件过大!")
      clearFile()
      return false;
    }

    //显示正在上传文件
    new showFile(singleFile)
    // 获取数据
    var uploadDate = new FormData();
    uploadDate.append("file",singleFile);
    // ajax上传
    new ajaxUpload(uploadDate);
  }

  // 现代浏览器上传
  function ajaxUpload (uploadDate){
    $.support.cors = true;
    ot = new Date().getTime();//获取上传开始时间
    $.ajax({
      type: "POST",
      url: config.uploadUrl,
      data: uploadDate,//这里上传的数据使用了formData 对象
      processData : false,
      //必须false才会自动加上正确的Content-Type
      contentType : false ,

      //这里咱们先拿到jQuery产生的 XMLHttpRequest对象,为其增长 progress 事件绑定,而后再返回交给ajax使用
      xhr: function(){
          xhr = $.ajaxSettings.xhr();
          var res = 0;
          xhr.upload.onprogress=progressFunc; //文件上传进度
          // 如下部分待测试
          // xhr.upload.onload = res = uploadComplete; //请求完成
          // xhr.upload.onerror =  uploadFailed; //请求失败
          // xhr.upload.onabort=abortFunc(); //文件上传取消
            return xhr;
        },
        success :function(data){
          if(config.callback){
            config.callback(data);
          }

          clearFile();
        },
        error: function(data){
        }
    });
  }

  // 文件上传进度
  function progressFunc(evt){
    // evt.total是须要传输的总字节,evt.loaded是已经传输的字节。若是evt.lengthComputable不为真,则evt.total等于0
    var nt = new Date().getTime();//获取上传开始时间
    if (evt.lengthComputable) {
      var num = Math.round(evt.loaded / evt.total * 100); //转换百分比
      if(num == 100){
          // 隐藏进度条
          // hiddenUploading($progressBar);
      }
      num += "%";
      $showFileItem.find(".f-itemPmgressBar .f-pmgress").css({
        width: num
      })

      // 计算速率oloaded
      var preTime = (nt-ot)/1000;
      var preLoad = evt.loaded - oloaded;
      oloaded = evt.loaded; //从新赋值已上传文件大小,用如下次计算
      var speed = preLoad/preTime;
      var unit = 'b'
        // 单位转换
      if(speed/1024 > 1){
        speed = speed/1024;
        unit = 'kb';
      }
      if(speed/1024 > 1){
        speed = speed/1024;
        unit = 'M';
      }
      // 小数只保留两位
      if(parseInt(speed)!=speed){
        speed = speed.toFixed(2);
      }
      // 显示速度
      $showFileItem.find(".f-itemSpeed").html(speed + unit + "/s" )
      
      // 上传完删除进度条及速度
      if(evt.total == evt.loaded){
        $showFileItem.find(".f-itemPmgressBar").remove();
        $showFileItem.find(".f-itemSpeed").remove();
      }
    }
  }

  // 显示文件数据
  function showFile(file){
    var size = file.size;
    var unit = 'b';
    
    // 单位转换
    if(size/1024 > 1){
      size = size/1024;
      unit = 'kb';
    }
    if(size/1024 > 1){
      size = size/1024;
      unit = 'M';
    }
    // 小数只保留两位
    if(parseInt(size)!=size){
      size = size.toFixed(2);
    }

    var itemTemp = '<div class="f-item-info" data-id="'+ fileId +'">\
                      <span class="f-itemName">'+ file.name +'</span>\
                      <span class="f-itemSize">('+ size + unit +')</span>\
                      <span class="f-itemPmgressBar"><span class="f-pmgress"></span></span>\
                      <span class="f-itemSpeed"></span>\
                      <span class="f-itemDel">delete</span>\
                    </div>'
    $showFileContainer.append(itemTemp);
    $showFileItem = $showFileContainer.find(".f-item-info[data-id = "+ fileId +"]")
  }
  
  // ie单个文件过滤限制
  function ie_singleFilefilter(){
    var fPath = $this.val() //文件路径+文件名
    var fName = fPath.substring(fPath.lastIndexOf("\\") + 1); //文件名
    var extensions = config.fileExtension.split(','); //容许拓展名
    var singleExtension = /\.[a-zA-Z]+$/.exec($this.val())[0].substring(1); // 单文件拓展名
    var isNext = false;

    // 格式限制
    if(extensions && extensions.length){
      for(var i = 0; i < extensions.length; i++){
        if(singleExtension == extensions[i].trim()){
          isNext = true;
        }
      }
    }
    // 判断isNext和singleExtension,为空或为false时提示
    if(!isNext){
      alert('文件格式不正确!');
      clearFile();
      return false;
    }

    var opt={
      iName: $this.prop('id')+' ',
      url: config.url,
      callback: config.callback,
      file: {
        name: fName
      }
    }
    // 动态建立iframe上传文件
    creatIframe(opt)
  }

  // 建立iframe及表单提交
  function creatIframe(opt){
    var $f_parent = $this.parent();
    var $iframe = $('<iframe name="'+ opt.iName +'" id="' + opt.iName + '" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"/>');
    var $form = $('<form method="post" style="display: none;" target="'+opt.iName+'" action="'+opt.url+'"  name="form_'+opt.iName+'" enctype="multipart/form-data" />');
    // 将控件插入form表单
    $("body").append($iframe);
    // var $form = $('body').find('form');
    $("body").append($form);
    $form.append("<input name='test' type='text'>").append($this);
    // $form.append($("#uploadFile"));

    // 表单提交
    $form.submit();
    // 获取数据,删除iframe
    $iframe.ready(function(){
      var data = $iframe.contents().find('body').html();
      if(opt.callback){
        opt.callback(data);
      }
      // 删除iframe,form
      $iframe.remove();
      $form.remove();
      // 控件放回原始位置
      $f_parent.append($this);
      ie_showFileinfo(opt);

      clearFile();
      return false
    })
  }

  // ie文件显示
  function ie_showFileinfo(opt){
    var itemTemp = '<div class="f-item-info" data-id="'+ fileId +'">\
      <span class="f-itemName">'+ opt.file.name +'</span>\
      <span class="f-itemDel">delete</span>\
    </div>'
    $showFileContainer.append(itemTemp);
    $showFileItem = $showFileContainer.find(".f-item-info[data-id = "+ fileId +"]")
  }

  //取消上传
  // abortFunc();
  function abortFunc(){
    // 关闭xhr
    xhr.abort();
    console.log("上传取消");
  }

  // 清空文件
  function clearFile(){
    if(browserInfo().browser.name == "Internet Explorer" && browserInfo().browser.edition*1 < 11){
      document.getElementById($this.prop("id")).outerHTML += '';
    }else{
      $this.val('');
    }
  }

  // 获取浏览器信息
  var browserInfo = function() {
    var NT = {
        '4.90': 'Windows ME',
        '4.0': 'Windows NT',
        '5.0': 'Windows 2000',
        '5.01': 'Windows 2000 SP1',
        '5.1': 'Windows XP',
        '5.2': 'Windows XP 64-bit / Windows Server 2003',
        '6.0': 'Windows Vista / Windows Server 2008',
        '6.1': 'Windows 7 / Windows Server 2008 R2',
        '6.2': 'Windows 8',
        '6.3': 'Windows 8.1',
        '6.4': 'Windows 10 Technical Preview',
        '10.0': 'Windows 10'
    }
    var userAgent = navigator.userAgent.toLowerCase();
    var platform = navigator.platform;
    var browserName = /(msie\s|trident.*rv:)([\w.]+)/.test(userAgent) ? 'Internet Explorer': (window.opera && window.opera.version ? 'Opera': ((userAgent.indexOf('edge') > -1) ? 'Microsoft Edge': ((userAgent.indexOf('chrome') > -1) ? 'Chrome': ((userAgent.indexOf("firefox") > -1) ? 'Firefox': (userAgent.indexOf('safari') > -1 ? 'Safari': 'Unknown')))));
    var browserVersion = browserName == 'Internet Explorer' ? (userAgent.indexOf('rv:') > -1 ? userAgent.match(/rv:[\d.]+/gi)[0].replace('rv:', '') : userAgent.match(/msie\s[\d.]+/gi)[0].replace('msie ', '')) : (browserName == 'Microsoft Edge' ? userAgent.match(/edge\/[\d.]+/gi)[0].replace('edge/', '') : (browserName == 'Firefox' ? userAgent.match(/firefox\/[\d.]+/gi)[0].replace('firefox/', '') : (browserName == 'Chrome' ? userAgent.match(/chrome\/[\d.]+/gi)[0].replace('chrome/', '') : (browserName == 'Safari' ? userAgent.match(/safari\/[\d.]+/gi)[0].replace('safari/', '') : 'Unknown'))));
    var browserEdition = browserVersion.split('.')[0];
    var kernelName = userAgent.indexOf('trident') > -1 ? 'Trident': userAgent.indexOf('edge') > -1 ? 'Edge': (((userAgent.indexOf('applewebkit') > -1) ? 'Webkit': ((userAgent.indexOf('gecko') > -1) ? 'Gecko': 'Unknown')));
    var kernelVersion = kernelName == 'Trident' ? (userAgent.match(/Trident\/[\d.]+/gi)[0].replace('Trident/', '')) : (browserName == 'Firefox' ? userAgent.match(/gecko\/[\d.]+/gi)[0].replace('gecko/', '') : ((browserName == 'Chrome' || browserName == 'Safari') ? userAgent.match(/applewebkit\/[\d.]+/gi)[0].replace('applewebkit/', '') : (browserName == 'Microsoft Edge' ? userAgent.match(/edge\/[\d.]+/gi)[0].replace('edge/', '') : 'Unknown')));
    var kernelEdition = kernelVersion.split('.')[0];
    var osName = userAgent.indexOf('android') > -1 ? 'Android': (userAgent.indexOf('ipad') > -1 ? 'iOS(iPad)': (userAgent.indexOf('iphone') > -1 ? 'iOS(iPhone)': userAgent.indexOf('windows phone') > -1 ? 'Windows Phone': (((platform == "Win32") || (platform == "Windows") ? 'Microsoft Windows': (navigator.platform == "Mac68K") || ((navigator.platform == "MacPPC") || (navigator.platform == "Macintosh") || (navigator.platform == "MacIntel") ? 'Apple Mac': 'Unknown')))));
    var osEdition = osName == 'Android' ? userAgent.match(/android\s[\d.]+/gi)[0].replace('android ', '') : ((osName == 'iOS(iPad)' || osName == 'iOS(iPhone)') ? userAgent.match(/os\s[\d_]+/gi)[0].replace('os ', '').replace('_', '.') : (osName == 'Windows Phone' ? userAgent.match(/windows\sphone\s[\d.]+/gi)[0].replace('windows phone ', '').replace('_', '.') : (osName == 'Microsoft Windows' ? (NT[userAgent.match(/windows\snt\s[\d.]+/gi)[0].replace('windows nt ', '')] ? NT[userAgent.match(/windows\snt\s[\d.]+/gi)[0].replace('windows nt ', '')] : 'Unknown') : 'Unknown')));
    return {
        browser: {
            name: browserName,
            edition: browserEdition,
            version: browserVersion
        },
        kernel: {
            name: kernelName,
            edition: kernelEdition,
            version: kernelVersion
        },
        os: {
            name: osName,
            edition: osEdition
        }
    };
  }
})(jQuery)