[关闭]
@lizlalala 2016-11-01T09:56:05.000000Z 字数 3230 阅读 1865

vue组件学习-upload

vue component upload


楼主最近项目结束无所事事=。=,加上之前用element的上传组件,用着有一点点不爽...就试着自己写了下上传组件,啊,写完的心理活动就是,虽然一直吐槽element的upload,但是真正轮到自己写才发现too young =。=。他们还是挺厉害的,特别是生命周期的封装上。
回归正题,楼主的组件,参照着element和ant-design的upload api,大致实现了如下功能:


  1. fileReader
    内置了几个事件,包括onprogress,onloadstart,onabort,onerror,onload,onloadend等几个事件,其中onloadend类似于finally操作,不管onerror还是onload,结束都会执行。在这边我们需要处理进度条,那么先看onprogress事件。event对象有这么几个有用的属性:

    • lengthComputable:决定浏览器是否可以对进度进行计算
    • total: 文件大小
    • loaded:已经上传的大小
    • result: 读取的结果,以data:url格式,可以用来作为src实现预览功能,当然我们也可以对file对象直接用URL.createObjectURL()来获取实现。
  2. 文件上传
    新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。
    它分成上传和下载两种情况。下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload对象。

    1. xhr.onprogress
    2. xhr.upload.onprogress

    要显示进度的话,可以在onprogress事件中获取信息。具体的跟上面一样。主要就是xhr和filereader其实都实现了progressEvent。具体的可以通过给event对象打log看下event.target就知道了。
    在filereader的onprogress中,e.target就是filereader,所以当freader.onload事件中可以调用e.target.result来获取src实现预览。如下:

    1. //filereader实现预览
    2. var reader = new FileReader();
    3. reader.onload = (function(aImg) {
    4. return function(e) {
    5. //e.target=== reader
    6. aImg.src = e.target.result;
    7. };
    8. })(img);
    1. //xhr中显示进度
    2. xhr.upload.onprogress = function updateProgress(e){
    3. //e.target===XMLHttpRequestUpload,即xhr.upload对象
    4. if(e.lengthComputable){
    5. e.percent = e.loaded/e.total*100;
    6. if(options.onProgress) options.onProgress(e);
    7. }
    8. };
  3. xhr
    xhr的时间周期
    执行顺序:

    1. 1. xhr open。打开连接
    2. 2. xhr send :在这个过程中,追踪请求xhr当前状态,用xhr.readyState来访问。
    3. - case 0: xhr对象刚被创建,尚未open
    4. - case 1: //opened
    5. - case 2: // headers_received。收到响应头
    6. - case 3: //loading 下载阶段
    7. - case 4: //done

    只有当 responseType 为"text"、""时,xhr对象上才有此属性,此时才能调用xhr.responseText

    从上面介绍的事件中,可以知道若xhr请求成功,就会触发xhr.onreadystatechange和xhr.onload两个事件。 一般倾向于 xhr.onload事件,因为xhr.onreadystatechange是每次xhr.readyState变化时都会触发,而不是xhr.readyState=4时才触发。

    1. //onload 当请求成功完成时触发,此时xhr.readystate=4
    2. const xhr = new XMLHttpRequest();
    3. xhr.onload = function onload(){
    4. if(xhr.status<200 ||(xhr.status>=300 && xhr.status!== 304))
    5. if(options.onError)
    6. options.onError(getError(action,xhr));
    7. else
    8. options.onSuccess(getResponseBody(xhr));
    9. }

    补充:

    • xhr.timeout的计算:从xhr.onloadstart(即xhr.send开始的时候)到xhr.onloadend
    • 可以在 send()之后再设置此xhr.timeout,但计时起始点仍为调用xhr.send()方法的时刻。
    • 当xhr为一个sync同步请求时,xhr.timeout必须置为0,否则会抛错。

      Throws an "InvalidAccessError" exception if async is false, the JavaScript global environment is a document environment, and either the timeout attribute is not zero, the withCredentials attribute is true, or the responseType attribute is not the empty string.


    注意事项:

    • 若在断网状态下调用xhr.send(data)方法,则会抛错:Uncaught NetworkError: Failed to execute 'send' on 'XMLHttpRequest'。一旦程序抛出错误,如果不 catch 就无法继续执行后面的代码,所以调用 xhr.send(data)方法时,应该用 try-catch捕捉错误。
      1. try{
      2. xhr.send(data)
      3. }catch(e) {
      4. //doSomething...
      5. };
  4. html5 drag drop

    • 一定要在dragover的处理事件中preventDefault(),否则默认行为是会跳转到另一个页面预览文件的。
    • 获取文件列表: e.dataTransfer.files
      e
    • 不会触发到input的change事件
  5. file上传

    1. <input type="file" style="display:none" id="fileInput" ref="fileInput" multiple @change="handleChange">
    2. <div @click="clickToChooseFile" for="fileInput">
    3. <p class="upload-hint">支持单文件/多文件上传,请选择image类型</p>
    4. </div>
    1. //模拟input点击
    2. clickToChooseFile(){
    3. this.$refs.fileInput.click();
    4. },

    一般是把input进行隐藏,用另一个自定义样式的div代替它,然后在click事件中去手动click该input。
    而监听文件变化的事件 onchange事件的参数是本地新变更(增加的files数组)。

references

  1. 你真的会使用XMLHttpRequest吗?
  2. HTML5 drag & drop 拖拽与拖放简介
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注