方案一:form表单上传
该方案优点是支持好,缺点刷新页面。
<form action="url" method="post" enctype="multipart/form-data"> <input type="file" name="file"><input type="submit" value="提交"> </form>
原理:enctype
就是form上传文件的重点。
值 | 描述 |
application/x-www-form-urlencoded |
默认。在发送前对所有字符进行编码(将空格转换为 "+" 符号,特殊字符转换为 ASCII HEX 值) |
multipart/form-data |
不对字符编码。当使用有文件上传控件的表单时,该值是必需的 |
text/plain |
将空格转换为 "+" 符号,但不编码特殊字符 |
方案二:form表单上传-优化方案一缺点
该方案的优点也是支持好,缺点是不支持跨域。
<form action="url" method="post" enctype="multipart/form-data" target="iframe"> <input type="file" name="file"><input type="submit" value="提交"> </form>
原理:通过target
把响应指向一个iframe
页面,之后拿到返回数据。
值 | 描述 |
_blank |
在新窗口/选项卡中打开 |
_self |
默认, 在同一框架中打开 |
_parent |
在父框架中打开。 |
_top |
在整个窗口中打开 |
framename |
在指定的 iframe 中打开 |
方案三:ajax上传-优化方案二缺点
该方案的缺点兼容问题-caniuse,兼容有两个方向一是低版本ie
不支持CORS
跨域,一个就是input
新加的Files
。优点就是异步,进度条,判断大小,处理,跨域。
var file = input.files[0]; var xhr = new XMLHttpRequest(); if (xhr.upload) { xhr.upload.addEventListener("progress", function(e) { console.log(file, e.loaded, e.total); }, false); // 文件上传成功或是失败 xhr.onreadystatechange = function(e) { if (xhr.readyState == 4) { if (xhr.status == 200) { console.log('成功', xhr.responseText) } else { console.log('失败') } } } // 开始上传 xhr.open("POST", 'url', true); xhr.send(file); }
方案四:ajax-formData上传-多字段多文件;
该方案基本同上,只不过使用了FormData
,缺点就是formData
的兼容
var formData = new FormData(); formData.append('file', input.files[0]); xhr.send(formData);
其他方案:
1. SWFupload Flash上传 2. jquery.form.js 其他插件上传
需求一:拖拽上传
使用drop
事件,获取e.dataTransfer
document.querySelector('body').addEventListener("drop", (e)=>{ e.preventDefault();//不写的话,就打开了 console.log(e.dataTransfer.files[0]) });
需求二:截图-粘贴-上传
使用paste
事件,获取e.clipboardData
document.querySelector('body').addEventListener("paste", (e)=>{ e.preventDefault();//不写的话,就打开了 console.log(e.clipboardData.files[0]) });
需求三:base64转换上传
场景发生在,一个和客户端交互的情况下,客户端选择的图片之后返给我了一个base64,让我上传这个,而且接口那边还不改,就要文件。代码写的比较啰嗦,其实也用不了这么多东西,当时也是第一次接触atob
、Blob
、ArrayBuffer
这些东西,就写成这样了。
function(data){ var _str = atob(data.base64Str) var _filePath = ((data.filePath.match(/.(jpg|jpeg|png|bmp)$/) || [])[1] || 'png').toLowerCase(); var _filePathHash = { jpg:'image/jpeg',jpeg:'image/jpeg',png: 'image/png',bmp:'application/x-bmp', } var pre = '--------------------------1\r\nContent-Disposition: form-data; name="file"; filename="1.png"\r\nContent-Type: '+_filePathHash[_filePath]+'\r\n\r\n'; var end = '\r\n--------------------------1--'; var buffer = new ArrayBuffer(_str.length); var uint8 = new Uint8Array(buffer); for(var i in _str){ uint8[i] = _str.charCodeAt(i); } var blob = new Blob([pre, uint8, end], {type: _filePathHash[_filePath]}); var oReq = new XMLHttpRequest(); oReq.open("POST", "url", true); oReq.setRequestHeader("Content-Type", "multipart/form-data; boundary=------------------------1") oReq.onreadystatechange=function(){if (oReq.readyState==4 && oReq.status==200){console.log(oReq.responseText); } oReq.send(blob);
需求四
上传一般来说都是要写样式的,不能说光是默认的input样式就ok,但是呢,样式又不是那么太好写,我们怎么办呢?
方案一
label
标签的for
去触发input
的单击,这样不就好了吗?input的样式不好写,那我们把他藏起来,给label
写样式。
方案二
input[type=file]
左边是一个input右边是个按钮,其实是按钮的样式不好改,那么我们外面包裹一层overlfow:hidden
,然后给input设置成一个极大,让他所有不一样的东西,都超出去,这样就是在能改动的区域改动了