@lizlalala
2016-11-01T09:56:05.000000Z
字数 3230
阅读 1865
vue
component
upload
楼主最近项目结束无所事事=。=,加上之前用element的上传组件,用着有一点点不爽...就试着自己写了下上传组件,啊,写完的心理活动就是,虽然一直吐槽element的upload,但是真正轮到自己写才发现too young =。=。他们还是挺厉害的,特别是生命周期的封装上。
回归正题,楼主的组件,参照着element和ant-design的upload api,大致实现了如下功能:
progress进度条
代码中实际上有两种:
最终进度条是按照post到服务器的进度来显示的)
fileReader
内置了几个事件,包括onprogress,onloadstart,onabort,onerror,onload,onloadend等几个事件,其中onloadend类似于finally操作,不管onerror还是onload,结束都会执行。在这边我们需要处理进度条,那么先看onprogress事件。event对象有这么几个有用的属性:
文件上传
新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。
它分成上传和下载两种情况。下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload对象。
xhr.onprogress
xhr.upload.onprogress
要显示进度的话,可以在onprogress事件中获取信息。具体的跟上面一样。主要就是xhr和filereader其实都实现了progressEvent。具体的可以通过给event对象打log看下event.target就知道了。
在filereader的onprogress中,e.target就是filereader,所以当freader.onload事件中可以调用e.target.result来获取src实现预览。如下:
//filereader实现预览
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
//e.target=== reader
aImg.src = e.target.result;
};
})(img);
//xhr中显示进度
xhr.upload.onprogress = function updateProgress(e){
//e.target===XMLHttpRequestUpload,即xhr.upload对象
if(e.lengthComputable){
e.percent = e.loaded/e.total*100;
if(options.onProgress) options.onProgress(e);
}
};
xhr
执行顺序:
1. xhr open。打开连接
2. xhr send :在这个过程中,追踪请求xhr当前状态,用xhr.readyState来访问。
- case 0: xhr对象刚被创建,尚未open
- case 1: //opened
- case 2: // headers_received。收到响应头
- case 3: //loading 下载阶段
- case 4: //done
只有当 responseType 为"text"、""时,xhr对象上才有此属性,此时才能调用xhr.responseText
从上面介绍的事件中,可以知道若xhr请求成功,就会触发xhr.onreadystatechange和xhr.onload两个事件。 一般倾向于 xhr.onload事件,因为xhr.onreadystatechange是每次xhr.readyState变化时都会触发,而不是xhr.readyState=4时才触发。
//onload 当请求成功完成时触发,此时xhr.readystate=4
const xhr = new XMLHttpRequest();
xhr.onload = function onload(){
if(xhr.status<200 ||(xhr.status>=300 && xhr.status!== 304))
if(options.onError)
options.onError(getError(action,xhr));
else
options.onSuccess(getResponseBody(xhr));
}
补充:
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.
try{
xhr.send(data)
}catch(e) {
//doSomething...
};
html5 drag drop
file上传
<input type="file" style="display:none" id="fileInput" ref="fileInput" multiple @change="handleChange">
<div @click="clickToChooseFile" for="fileInput">
<p class="upload-hint">支持单文件/多文件上传,请选择image类型</p>
</div>
//模拟input点击
clickToChooseFile(){
this.$refs.fileInput.click();
},
一般是把input进行隐藏,用另一个自定义样式的div代替它,然后在click事件中去手动click该input。
而监听文件变化的事件 onchange事件的参数是本地新变更(增加的files数组)。