关于js异步上传文件
好久没登录博客园了,今天来一发分享。
最近项目里有个需求,上传文件(好吧,这种需求很常见,这也不是第一次遇到了)。当时第一想法就是直接用form表单提交(原谅我以前就是这么干的),不过表单里不仅有文件还有别的信息需要交互,跟后端商量后决定文件单独上传,获取到服务器端返回的文件地址在和表单一起提交。这里就需要异步上传文件。
在网上扒了扒相关的内容,发现还真不少,阮一峰老师的这篇文章(文件上传的渐进式增强)就介绍的很具体,下面就谈谈自己在实战中遇到的一些问题的感受吧。
先看看效果,实现了哪些功能
(好吧,就一个按钮而已,搞得神神秘秘,嘿嘿)
<button type="button" class="btn" @click="upload">点击上传文件</button>
给按钮绑定了一个点击事件,下面看看点击事件方法里做了什么
methods: {
upload: function(){
myUpload({
url: window.location.protocol + '//' + window.location.host + '/crm/upload',
maxSize: 10,
beforeSend: function(file){
},
callback: function(res){
var data = JSON.parse(res);
pageCont.attachmentUrl = data.url;
},
uploading: function(pre){
pageCont.uploadCont.display = 'block';
pageCont.uploadStyle.width = pre * 2 + 'px';
pageCont.pre = pre;
}
});
}
}
按钮绑定的点击事件执行了upload方法,在upload方法里调用了一下myUpload方法,并传递了一些配置信息进去,稍后说下这些配置信息。先看看myUpload的具体实现:
初始化了一个FormData对象和一个XMHttpResquest对象,创建一个type为file的input,并触发一次该input的click,如下
var fd = new FormData(),
xhr = new XMLHttpRequest(),
input;
input = document.createElement('input');
input.setAttribute('id', 'myUploadInput');
input.setAttribute('type', 'file');
input.setAttribute('name', 'file');
document.body.appendChild(input);
input.style.display = 'none';
input.click();
监听刚才创建的input的change事件,并作在里面做相应处理
input.onchange = function(){
if(!input.value){return;}
if(option.maxSize && input.files[0].size > option.maxSize * 1024 * 1024){
dialog({
title: '提示',
content: '请上传小于'+option.maxSize+'M的文件',
okValue: '确定',
ok: function () {}
}).showModal();
return;
}
if(option.beforeSend instanceof Function){
if(option.beforeSend(input) === false){
return false;
}
}
fd.append('file', input.files[0]);
xhr.open('post', option.url);
xhr.onreadystatechange = function(){
if(xhr.status == 200){
if(xhr.readyState == 4){
if(option.callback instanceof Function){
option.callback(xhr.responseText);
}
}
}else{
if(!(dialog.get('uploadfail'))){
dialog({
id: 'uploadfail',
title: '提示',
content: '上传失败',
okValue: '确定',
ok: function () {}
}).showModal();
}
}
}
xhr.upload.onprogress = function(event){
var pre = Math.floor(100 * event.loaded / event.total);
if(option.uploading instanceof Function){
option.uploading(pre);
}
}
xhr.send(fd);
}
解释下上面的代码。input的change事件触发后,首先判断了下当前是否选择了文件
if(!input.value){return;}
一开始我是没做这个判断的,在后来的测试过程中发现,当上传一次文件后,再次点击按钮上传,打开文件选择框,然后不选择文件,而是点击取消按钮,change事件也触发了,导致后面的代码也会执行,显然这不合理,故加了这个判断。
然后限制了下上传文件的大小(这样的事能够前端处理就不要交给服务端来验证了),当文件大小超过最大限制,就会弹框提示
if(option.maxSize && input.files[0].size > option.maxSize * 1024 * 1024){
dialog({
title: '提示',
content: '请上传小于'+option.maxSize+'M的文件',
okValue: '确定',
ok: function () {}
}).showModal();
return;
}
然后加了一个文件上传前的操作,可以在文件上传前做一些处理,如进度条的显示,图片预览等等
if(option.beforeSend instanceof Function){
if(option.beforeSend(input) === false){
return false;
}
}
接下来将文件append到formData对象里,使用字段名‘file’,该字段名是服务端接收文件时使用的字段名
fd.append('file', input.files[0]);
然后就是使用XMLHttpRequest对象向服务端发送数据了
xhr.open('post', option.url);
xhr.onreadystatechange = function(){
if(xhr.status == 200){
if(xhr.readyState == 4){
if(option.callback instanceof Function){
option.callback(xhr.responseText);
}
}
}else{
if(!(dialog.get('uploadfail'))){
dialog({
id: 'uploadfail',
title: '提示',
content: '上传失败',
okValue: '确定',
ok: function () {}
}).showModal();
}
}
}
xhr.upload.onprogress = function(event){
var pre = Math.floor(100 * event.loaded / event.total);
if(option.uploading instanceof Function){
option.uploading(pre);
}
}
xhr.send(fd);
在向服务端发送数据时,使用了监听了一下progress事件,主要是为了进行上传进度的显示,上述代码中,
var pre = Math.floor(100 * event.loaded / event.total);
获取上传的百分比,能够拿到这个值,页面上就可以展示各种各样的上传进度效果了。
差不多介绍完了,下面补充一下使用中遇到的问题:
问题一:文件在上传的过程中,使用JSON.parse()序列化服务端返回的json字符串报错(傻啊,文件还在上传,服务端怎么会返回数据啊)。
事情是这样的,一开始,我在readystatechange里只监听了状态码是否是200,如果是就说明通了,然后执行回调,在回调里处理服务端返回的数据,但是通了不一定代表服务端已经返回了数据,所以就出现了上面的错误,所以后来在判断了status是否为200后,还判断了readyState,以确保服务端已处理完毕并返回数据在执行回调
if(xhr.status == 200){
if(option.callback instanceof Function){
option.callback(xhr.responseText);
}
}
问题二:重复创建input。每次点击按钮上传文件后,页面都会多一个type=file的input感觉不是很好(个人癖好吧),所以对最开始的初始化代码做了下优化,判断当前页面是否存在刚才创建的input,存在就直接使用,不存在就创建,如下
if(document.getElementById('myUploadInput')){
input = document.getElementById('myUploadInput');
}else{
input = document.createElement('input');
input.setAttribute('id', 'myUploadInput');
input.setAttribute('type', 'file');
input.setAttribute('name', 'file');
document.body.appendChild(input);
input.style.display = 'none';
}
好了,就这么多了。看看效果



因个人知识面有限,如有错误,还请指正。转载请注明出处,谢谢!
关于js异步上传文件的更多相关文章
- 利用ajaxfileupload.js异步上传文件
1.引入ajaxfileupload.js 2.html代码 <input type="file" id="enclosure" name="e ...
- JS异步上传文件
直接调用Upload(option)方法,即可上传文件,不需要额外的插件辅助,采用原生js编写. /* *异步上传文件 *option参数 **url:上传路径 **data:上传的其他数据{id:& ...
- Node.js——异步上传文件
前台代码 submit() { var file = this.$refs.fileUpload.files[0]; var formData = new FormData(); formData.a ...
- 关于JQuery.form.js异步上传文件点滴
好久没动代码了,前几天朋友委托我帮忙给做几个页面,其中有个注册带图片上传的页面.已之前的经验应该很快就能搞定,没想到的是搞了前后近一天时间.下面就说说异步上传的重要几个点,希望自己下次遇到此类问题的时 ...
- vue.js异步上传文件前后端代码
上传文件前端代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type&q ...
- Servlet异步上传文件
这里需要用到插件ajaxfileupload.js,jar包:commons-fileupload-1.3.2.jar,commons-io-2.5.jar 注意红色部分的字!!!! 1.创建一个we ...
- struts2 jquery ajaxFileUpload 异步上传文件
网上搜集的,整理一下. 一.ajaxFileUpload 实现异步上传文件利用到了ajaxFileUpload.js这个文件,这是别人开发的一个jquery的插件,可以实现文件的上传并能够和strut ...
- 【转】JQuery插件ajaxFileUpload 异步上传文件(PHP版)
前几天想在手机端做个异步上传图片的功能,平时用的比较多的JQuery图片上传插件是Uploadify这个插件,效果很不错,但是由于手机不支持flash,所以不得不再找一个文件上传插件来用了.后来发现a ...
- 异步上传文件,ajax上传文件,jQuery插件之ajaxFileUpload
http://www.cnblogs.com/kissdodog/archive/2012/12/15/2819025.html 一.ajaxFileUpload是一个异步上传文件的jQuery插件. ...
随机推荐
- centos常用操作
文件夹赋权chmod -R 777 文件夹 zip压缩和unzip解压缩命令详解以下命令均在/home目录下操作cd /home #进入/home目录1.把/home目录下面的mydata目录压缩为m ...
- 2016 icpc-ec-final
一不小心惨变旅游队,不过上海的风景不错 顺带找其他队交流一下集训经验...或许可以成为选拔和集训16级的依据 A.直接模3就可以了,2^(3*n)%7=1 L.每场比赛3种情况,穷举就可以了 D.刚开 ...
- [原]ComFriendlyWaitForSingleObject
structThreadParam { unsignedint p1;// +00h ebp-24h unsignedint p2;// +04h ebp-20h unsignedint cookie ...
- https 单向认证和双向认证配置
HTTPS 是我们开发中经常用到的通信加密技术,能有效保护我们网络访问中的安全,本文主要讲解单向 和 双向 https 的配置.关于https 的实现原理在这里我就不赘述了,附上阮一峰老师的关于htt ...
- Codeforces Round #389 (Div. 2, Rated, Based on Technocup 2017 - Elimination Round 3) A
Description Santa Claus is the first who came to the Christmas Olympiad, and he is going to be the f ...
- laravel的配置文件
app/config 中的配置说明 1 在 app/config 文件夹中经常配置的一般有两个文件:app.php 和 database.php 两个文件,他们一个是配置项目杂项的.一个是配置数据 ...
- Navigator
Navigator 这是一个简单的例子,用Navigator来跳转页面,页面之间传递参数 (代码是ES6语法写的): import React from 'react'; import { V ...
- web前端之HTML中元素的区分
作为前端人员,我们就是要与各种超文本标记打交道,用到各种不同的标签元素.在使用的时候不知道有没有注意到他们的分类归属?现在就来说一说博主的见解: 目前博主总结了三种分类方法:一是按封闭来划分,一是按显 ...
- RSA5、RSA6
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 如何获得APP内部资源
安装一个iTools(百度一下就有) 用USB连接设备,打开iTools