arale插件-uploadjs源码解读

1.JS补遗

outerHeight()包括内边距和边框,输入includeMargin参数就可以包括外边距

innerHeight()包括内边距、不包括边框

height()随浏览器的盒模式作相应的改变

css(‘height’)包含px单位

 

offset()获取元素相对文档的偏移量,.left.top取左右偏移及上下偏移

 

2.jQuery补遗

jQuery工具函数

$.extend(target,[object1],[objectN])

object1……objectN合并到target对象中,键值相同的项将被替换

用途:替换默认的配置项$.extend(default,options)

代码实现:

 

$.extend([deep],target,object1,[objectN])

深拷贝的方式,子项也将被递归合并

 

$.extend(object)

扩展jQuery类,即为静态方法

 

$.fn.extend(object)

扩展jQuery对象的方法,即为原型属性上的公有方法

 

$.each(object, [callback])

遍历数组或者对象

 

$.grep(array, callback, [invert])

根据回调函数过滤数组,invert默认为false,回调函数返回值为true的项构成结果集

 

$.makeArray(obj)

将类数组对象arguments转化成数组,可以应用数组的方法

 

$.map(arr|obj,callback)

对数组元素进行操作后构成新数组,利用null以及[]的形式裁断或增加数组元素的数目

 

$.inArray(value,array,[fromIndex])

返回value在数组中的索引,不在数组中返回-1fromIndex起始位置

 

$.merge(first,second)

第二个数组的元素跟在第一个数组的元素后面输出,并替换第一个数组

 

$.unique(array)

处理DOM元素,删除重复的数组

 

$.parseJSON(json)

json形式的字符串(双引号包裹)转化成json对象输出,可以用键值对读取

 

jQuery-ajax

暂缺

 

3.HTML5新技术

FileList对象ie8无法用输入框获取文件对象)

<input type=’file’>元素的files属性中包含文件对象,设置multiple属性可以支持多文件上传,该File对象继承Blob,包含sizetypeMIME类型)属性、slice方法,在此基础上又扩展出namelastModifiedDate两个属性

获取该对象可使用

document.getElementById(‘idname’).files[0]

 

FileReader对象

首先创建一个FileReader实例,其次有三个方法可供调用,均为异步读取,通过监听对象的onload事件读取result数据,abort方法停止读取

readAsBinaryString(Blob blob)传入blob对象(file对象继承blob对象),然后将读取数据的结果作为二进制的形式放大片FileReader对象的result属性里;

readAsText(Blob blob, optional DOMString encoding)传入blob对象、编码格式,以文本字符串形式存储在result中;

readAsDataURL(Blob blob)传入blob对象,读取内容作为url属性,处理图片的src地址

调用方法

var resultFile = document.getElementById("fileDemo").files[0];
if (resultFile) {
    var reader = new FileReader();
    reader.readAsDataURL(resultFile);
    reader.onload = function (e) {
        console.log(this.result) ;
    }; 
}

 

http://www.cnblogs.com/fly_dragon/archive/2012/06/02/2532035.html

 

FormData对象

首先创建一个FormData实例,然后使用append方法往该实例中加入键值对,可以是简单的数据,也可以是blob对象或者文件对象,再通过ajax的方式将该实例发送给后台;

另一种方式是使用表单元素创建实例,如new FormData(someformelement)

示例(问题是后台怎么接受):

var newFormData = new FormData(someFormElement);
newFormData.append("accountnum", 123456);
newFormData .append("userfile", fileInputElement.files[0]);
var oFileBody = "<a id="a"><b id="b">hey!</b></a>"; // Blob对象包含的文件内容
var oBlob = new Blob([oFileBody], { type: "text/xml"});
newFormData.append("webmasterfile", oBlob);

 

http://www.cnblogs.com/lhb25/p/html5-formdata-tutorials.html

 

4.upload插件的使用

配置项(form表单上传文件的时候,需要添加enctype="multipart/form-data"):

trigger触发元素,即点击后能弹出对话框的元素,和form<input type=’file’>同等大小

accept限定上传文件的类型,<input type=’file’>accept属性

action上传地址,formaction属性,ajaxurl,关联后台的方法或url

name文件的名字

data附带的数据,form通过input上传,ajax通过额外的上传数据

multiple是否允许多文件上传

change上传文件的输入框改变时调用,上下文是上传输入框,参数是文件对象

successerror上传成功或失败时调用,form通过iframe加载解析文档内容,ajax直接返回

progress上传进度的函数function(event, position, total, percent, files){}

 

调用方式是new出一个Uploader实例或者new出一个MultipleUploader实例(针对多个上传文件input的情况,以数组形式传入相应的trigger

示例:

var uploader = new Uploader({
    trigger: '.upload-btn',
    name: 'image',
    action: '/upload',
    accept: 'image/*',
    data: {'xsrf': 'hash'},
    multiple: true,
    error: function(file) {
        alert(122);
    },
    success: function(response) {
        alert(response);
    },
    progress: function(event, position, total, percent, files) {
        console.log(percent);
    }
});

 

5.upload插件的源码

架构:

对支持html5的浏览器使用ajax的方式上传,不支持的浏览器使用表单上传,通过iframe禁止页面刷新,以及获取后台返回的响应

源码:

var iframeCount = 0;

function Uploader(options) {
  if (!(this instanceof Uploader)) {
    return new Uploader(options);
  }
  if (isString(options)) {
    options = {trigger: options};
  }

  var settings = {
    trigger: null,
    name: null,
    action: null,
    data: null,
    accept: null,
    change: null,
    error: null,
    multiple: true,
    success: null
  };
  if (options) {
    $.extend(settings, options);
  }
  var $trigger = $(settings.trigger);// 触发元素,创建的form和<input type='file'>和它同等大小,点击弹出文件选择对话框

  settings.action = settings.action || $trigger.data('action') || '/upload';
  settings.name = settings.name || $trigger.attr('name') || $trigger.data('name') || 'file';
  settings.data = settings.data || parse($trigger.data('data'));
  settings.accept = settings.accept || $trigger.data('accept');
  settings.success = settings.success || $trigger.data('success');
  this.settings = settings;

  this.setup();
  this.bind();
}

Uploader.prototype.setup = function() {
  this.form = $(
    '<form method="post" enctype="multipart/form-data"'
    + 'target="" action="' + this.settings.action + '" />'
  );

  //调用newIframe函数创建新的iframe框架,createInputs创建输入框,键值对作为name和value
  this.iframe = newIframe(); 
  this.form.attr('target', this.iframe.attr('name'));

  var data = this.settings.data;
  this.form.append(createInputs(data)); 
  if (window.FormData) {
    this.form.append(createInputs({'_uploader_': 'formdata'}));
  } else {
    this.form.append(createInputs({'_uploader_': 'iframe'}));
  }

  var input = document.createElement('input');
  input.type = 'file';
  input.name = this.settings.name;
  if (this.settings.accept) { 
    input.accept = this.settings.accept;
  }
  if (this.settings.multiple) {
    input.multiple = true;
    input.setAttribute('multiple', 'multiple');
  }
  this.input = $(input);

  var $trigger = $(this.settings.trigger);
  this.input.attr('hidefocus', true).css({
    position: 'absolute',
    top: 0,
    right: 0,
    opacity: 0,
    outline: 0,
    cursor: 'pointer',
    height: $trigger.outerHeight(),
    fontSize: Math.max(64, $trigger.outerHeight() * 5)
  });
  this.form.append(this.input);
  this.form.css({
    position: 'absolute',
    top: $trigger.offset().top, 
    left: $trigger.offset().left,
    overflow: 'hidden',
    width: $trigger.outerWidth(),
    height: $trigger.outerHeight(),
    zIndex: findzIndex($trigger) + 10
  }).appendTo('body');
  return this;
};

Uploader.prototype.bind = function() {
  var self = this;
  var $trigger = $(self.settings.trigger);
  $trigger.mouseenter(function() {// 不是多此一举???
    self.form.css({
      top: $trigger.offset().top,
      left: $trigger.offset().left,
      width: $trigger.outerWidth(),
      height: $trigger.outerHeight()
    });
  });
  self.bindInput();
};

Uploader.prototype.bindInput = function() {
  var self = this;
  self.input.change(function(e) {
    // ie9 don't support FileList Object
    self._files = this.files || [{
      name: e.target.value
    }];
    var file = self.input.val();
    if (self.settings.change) {
      self.settings.change.call(self, self._files);
    } else if (file) {
      return self.submit();
    }
  });
};

Uploader.prototype.submit = function() {
  var self = this;
  if (window.FormData && self._files) {
    var form = new FormData(self.form.get(0));// 表单元素即包含上传输入框,为什么还要往formdata对象中添加文件???
    form.append(self.settings.name, self._files);

    var optionXhr;
    if (self.settings.progress) {
      var files = self._files;
      optionXhr = function() {
        var xhr = $.ajaxSettings.xhr();
        if (xhr.upload) {
          xhr.upload.addEventListener('progress', function(event) {
            var percent = 0;
            console.log(event.loaded)
            var position = event.loaded || event.position; /*event.position is deprecated*/
            var total = event.total;
            if (event.lengthComputable) {
                percent = Math.ceil(position / total * 100);
            }
            self.settings.progress(event, position, total, percent, files);
          }, false);
        }
        return xhr;
      };
    }
    $.ajax({
      url: self.settings.action,
      type: 'post',
      processData: false,
      contentType: false,
      data: form,
      xhr: optionXhr,
      context: this,
      success: self.settings.success,
      error: self.settings.error
    });
    return this;
  } else {
    self.iframe = newIframe();// 之前创建一个iframe,何必再创建???
    self.form.attr('target', self.iframe.attr('name'));
    $('body').append(self.iframe);
    self.iframe.one('load', function() {
      // https://github.com/blueimp/jQuery-File-Upload/blob/9.5.6/js/jquery.iframe-transport.js#L102
      // Fix for IE endless progress bar activity bug
      // (happens on form submits to iframe targets):
      $('<iframe src="javascript:false;"></iframe>')
        .appendTo(self.form)
        .remove();// 添加再删除是怎么回事???
      var response;
      try {
        response = $(this).contents().find("body").html();// contents()获取直接子节点,包含文本节点和html节点
      } catch (e) {
        response = "cross-domain";
      }
      $(this).remove();
      if (!response) {
        if (self.settings.error) {// ajax上传成功失败时调用接口,表单上传需要传入相应的参数
          self.settings.error(self.input.val());
        }
      } else {
        if (self.settings.success) {
          self.settings.success(response);
        }
      }
    });
    self.form.submit();
  }
  return this;
};

//重复上传多个文件的时候使用,以及上传成功或失败时使用
Uploader.prototype.refreshInput = function() {
  //replace the input element, or the same file can not to be uploaded
  var newInput = this.input.clone();
  this.input.before(newInput);
  this.input.off('change');
  this.input.remove();
  this.input = newInput;
  this.bindInput();
};

Uploader.prototype.change = function(callback) {
  if (!callback) {
    return this;
  }
  this.settings.change = callback;
  return this;
};

Uploader.prototype.success = function(callback) {
  var me = this;
  this.settings.success = function(response) {
    me.refreshInput();
    if (callback) {
      callback(response);
    }
  };

  return this;
};

Uploader.prototype.error = function(callback) {
  var me = this;
  this.settings.error = function(response) {
    if (callback) {
      me.refreshInput();
      callback(response);
    }
  };
  return this;
};

Uploader.prototype.enable = function(){
  this.input.prop('disabled', false);
  this.input.css('cursor', 'pointer');
};

Uploader.prototype.disable = function(){
  this.input.prop('disabled', true);
  this.input.css('cursor', 'not-allowed');
};

// Helpers
// -------------

function isString(val) {
  return Object.prototype.toString.call(val) === '[object String]';
}

function createInputs(data) {
  if (!data) return [];

  var inputs = [], i;
  for (var name in data) {
    i = document.createElement('input');
    i.type = 'hidden';
    i.name = name;
    i.value = data[name];
    inputs.push(i);
  }
  return inputs;
}

function parse(str) {// 解析a=3&b=4形式的字符串
  if (!str) return {};
  var ret = {};

  var pairs = str.split('&');
  var unescape = function(s) {
    return decodeURIComponent(s.replace(/\+/g, ' '));
  };

  for (var i = 0; i < pairs.length; i++) {
    var pair = pairs[i].split('=');
    var key = unescape(pair[0]);
    var val = unescape(pair[1]);
    ret[key] = val;
  }

  return ret;
}

function findzIndex($node) {
  var parents = $node.parentsUntil('body');// parentsUntil方法遍历寻找祖先元素,源自jquery
  var zIndex = 0;
  for (var i = 0; i < parents.length; i++) {
    var item = parents.eq(i);
    if (item.css('position') !== 'static') {
      zIndex = parseInt(item.css('zIndex'), 10) || zIndex;
    }
  }
  return zIndex;
}

function newIframe() {
  var iframeName = 'iframe-uploader-' + iframeCount;
  var iframe = $('<iframe name="' + iframeName + '" />').hide();
  iframeCount += 1;
  return iframe;
}

//多个input元素时候的调用方式
function MultipleUploader(options) {
  if (!(this instanceof MultipleUploader)) {
    return new MultipleUploader(options);
  }

  if (isString(options)) {
    options = {trigger: options};
  }
  var $trigger = $(options.trigger);

  var uploaders = [];
  $trigger.each(function(i, item) {
    options.trigger = item;
    uploaders.push(new Uploader(options));
  });
  this._uploaders = uploaders;
}
MultipleUploader.prototype.submit = function() {
  $.each(this._uploaders, function(i, item) {
    item.submit();
  });
  return this;
};
MultipleUploader.prototype.change = function(callback) {
  $.each(this._uploaders, function(i, item) {
    item.change(callback);
  });
  return this;
};
MultipleUploader.prototype.success = function(callback) {
  $.each(this._uploaders, function(i, item) {
    item.success(callback);
  });
  return this;
};
MultipleUploader.prototype.error = function(callback) {
  $.each(this._uploaders, function(i, item) {
    item.error(callback);
  });
  return this;
};
MultipleUploader.prototype.enable = function (){
  $.each(this._uploaders, function (i, item){
    item.enable();
  });
  return this;
};
MultipleUploader.prototype.disable = function (){
  $.each(this._uploaders, function (i, item){
    item.disable();
  });
  return this;
};

 

你可能感兴趣的:(arale插件-uploadjs源码解读)