ittiam
8/28/2017 - 3:30 AM

ajax 上传文件

ajax 上传文件

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory();
  } else {
    // Browser globals
    root.OssUploader = factory();
  }
})(this, function() {
  var _extend = function(dst, src) {
    for (var i in src) {
      if (Object.prototype.hasOwnProperty.call(src, i) && src[i]) {
        dst[i] = src[i];
      }
    }
  };

  var guid = (function() {
    var counter = 0;

    return function(prefix) {
      var guid = new Date().getTime().toString(32),
        i;

      for (i = 0; i < 5; i++) {
        guid += Math.floor(Math.random() * 65535).toString(32);
      }

      return (prefix || 'o_') + guid + (counter++).toString(32);
    };
  })();

  var parseSizeStr = function(size) {
    if (typeof size !== 'string') {
      return size;
    }

    var muls = {
        t: 1099511627776,
        g: 1073741824,
        m: 1048576,
        k: 1024
      },
      mul;

    size = /^([0-9]+)([mgk]?)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, ''));
    mul = size[2];
    size = +size[1];

    if (muls.hasOwnProperty(mul)) {
      size *= muls[mul];
    }
    return size;
  };

  function getSuffix(filename) {
    var tempArr = filename.split('.');
    var ext;
    if (tempArr.length === 1 || (tempArr[0] === '' && tempArr.length === 2)) {
      ext = '';
    } else {
      ext = tempArr.pop().toLowerCase();
    }
    return ext;
  }

  function getError(action, option, xhr) {
    var msg;
    if (xhr.response) {
      msg = xhr.status + ' ' + (xhr.response.error || xhr.response);
    } else if (xhr.responseText) {
      msg = xhr.status + ' ' + xhr.responseText;
    } else {
      msg = 'fail to post ' + action + ' ' + xhr.status;
    }

    const err = new Error(msg);
    err.status = xhr.status;
    err.method = 'post';
    err.url = action;
    return err;
  }

  function getBody(xhr) {
    var text = xhr.responseText || xhr.response;
    if (!text) {
      return text;
    }

    try {
      return JSON.parse(text);
    } catch (e) {
      return text;
    }
  }

  function upload(option) {
    if (typeof XMLHttpRequest === 'undefined') {
      return;
    }

    var xhr = new XMLHttpRequest();
    var action = option.action;

    if (xhr.upload) {
      xhr.upload.onprogress = function progress(e) {
        if (e.total > 0) {
          e.percent = e.loaded / e.total * 100;
        }
        option.onProgress(e);
      };
    }

    var formData = new FormData();

    if (option.data) {
      Object.keys(option.data).map(key => {
        formData.append(key, option.data[key]);
      });
    }

    formData.append(option.filename, option.file);

    xhr.onerror = function error(e) {
      option.onError(e);
    };

    xhr.onload = function onload() {
      if (xhr.status < 200 || xhr.status >= 300) {
        return option.onError(getError(action, option, xhr));
      }

      option.onSuccess(getBody(xhr));
    };

    xhr.open('post', action, true);

    if (option.withCredentials && 'withCredentials' in xhr) {
      xhr.withCredentials = true;
    }

    const headers = option.headers || {};

    for (var item in headers) {
      if (headers.hasOwnProperty(item) && headers[item] !== null) {
        xhr.setRequestHeader(item, headers[item]);
      }
    }
    xhr.send(formData);
    return xhr;
  }

  function OssUploader(element, options) {
    if (element && typeof element === 'string') {
      this.element = document.querySelector(element);
    } else {
      this.element = element;
    }

    if (!this.element) {
      throw new Error('file does not exist!');
    }

    this.conf = _extend(
      {
        maximum: 5,
        size: 1024 * 1024 * 2,
        multi_selection: true, // 是否多选
        prevent_duplicates: false, // 是否允许提交重复的文件
        object_name_type: 'unique_name',
        auto_start: true,
        withCredentials: false,
        data: null,
        name: '',
        action: 'get',
        onStart: function() {},
        onProgress: function() {},
        onSuccess: function() {},
        onError: function() {},
        beforeUpload: null
      },
      options
    );

    this.errors = {
      size: ''
    };

    this._signature = {
      expire: 0
    };

    this.max = this.conf.maximum;
    this.size = this.conf.size;

    this._init();
  }

  OssUploader.prototype = {
    _init: function() {
      if (this.max > 1 && this.conf.multi_selection) {
        this.element.setAttribute('multiple', true);
      } else {
        this.element.removeAttribute('multiple');
      }

      this._bindEvents();
    },

    _bindEvents: function() {
      var _self = this;
      this.element.addEventListener('change', function(evt) {
        var files = evt.target.files;

        if (!files) return;
        _self.uploadFiles(files);
      });
    },

    uploadFiles: function(files) {
      var _self = this;
      let postFiles = Array.prototype.slice.call(files);
      if (!this.multiple) {
        postFiles = postFiles.slice(0, 1);
      }
      if (postFiles.length === 0) {
        return;
      }
      postFiles.forEach(function(rawFile) {
        rawFile.uid = guid();
        _self.conf.onStart(rawFile);
        if (_self.conf.auto_start) _self.upload(rawFile);
      });

      this.element.value = null;
    },

    upload: function(rawFile, file) {
      if (!this.conf.beforeUpload) {
        return this.post(rawFile);
      }

      this.conf.beforeUpload(rawFile, function(processedFile) {
        if (Object.prototype.toString.call(processedFile) === '[object File]') {
          this.post(processedFile);
        } else {
          this.post(rawFile);
        }
      });
    },

    abort(file) {
      var reqs = this.reqs;
      if (file) {
        var uid = file;
        if (file.uid) uid = file.uid;
        if (reqs[uid]) {
          reqs[uid].abort();
        }
      } else {
        Object.keys(reqs).forEach(function(uid) {
          if (reqs[uid]) reqs[uid].abort();
          delete reqs[uid];
        });
      }
    },

    post(rawFile) {
      var _self = this;
      var uid = rawFile.uid;
      const options = {
        headers: this.headers,
        withCredentials: this.conf.withCredentials,
        file: rawFile,
        data: this.conf.data,
        filename: this.conf.name,
        action: this.conf.action,
        onProgress: e => {
          _self.conf.onProgress(e, rawFile);
        },
        onSuccess: res => {
          _self.conf.onSuccess(res, rawFile);
          delete this.reqs[uid];
        },
        onError: err => {
          _self.conf.onError(err, rawFile);
          delete this.reqs[uid];
        }
      };

      var req = upload(options);
      this.reqs[uid] = req;
    },

    _varifyFile: function(file) {}
  };

  return OssUploader;
});