上传方式
一、Form && Input
采用传统的form表单或异步ajax上传。至于以前通过iframe来进行异步上传,这里不详细介绍,想了解可以看http://www.ruanyifeng.com/blog/2012/08/file_upload.html。
Tips:
- input file标签设置accept属性进行文件选择过滤,该属性的值必须为一个逗号分割的列表,包含了多个唯一的内容类型声明:
- 以 STOP 字符 (U+002E) 开始的文件扩展名。(例如:".jpg,.png,.doc")一个有效的 MIME 类型,但没有扩展名
- audio/* 表示音频文件 HTML5
- video/* 表示视频文件 HTML5
- image/* 表示图片文件
- 设置multiple属性可以进行设置为多选。
- 设置capture属性可以进行设置打开摄像拍照或者录像。multiple属性和capture属性不能同时生效。(移动端里在安卓和ios上有不同的表现,但效果都一样)
//Capture Image:
//Capture Audio:
//Capture Video:
接着就是通过js来获取input里的value并进行下一步的操作
var fileInput1 = document.getElementById("fileInput1");
fileInput1.addEventListener('change', function(event) {
var file = fileInput1.files[0];
// 或file = fileInput1.files.item(0);
console.log(file);
document.getElementById('showFile1').innerHTML= file.name
}, false);
function handleSubmit(_this) {
var form = $(_this);
// mulitipart form,如文件上传类
var formData = new FormData();
formData.append('files', $('#fileInput1')[0].files[0]);
//var formData = new FormData(form[0]);
$.ajax({
type: form.attr('method'),
url: form.attr('action'),
data: formData,
mimeType: "multipart/form-data",
contentType: false,
cache: false,
processData: false
})
.success(function (res) {
//成功提交
console.log(res)
document.getElementById('result').innerHTML= '上传成功'
})
.error(function (jqXHR, textStatus, errorThrown) {
//错误信息
document.getElementById('result').innerHTML= '上传失败'
});
return false;
}
Tips: 预防form表单提交的跳转action。
- ajax中的resquest-header: multipart/form-data
- 参数及文件均需要使用
new FormData()
实例 append()
这里需要对file对象进一步的说明:
- lastModifiedDate:文件对象最后修改的日期
- name:文件名,只读字符串,不包含任何路径信息.
- size:文件大小,单位为字节,只读的64位整数.
- type:MIME类型,只读字符串,如果类型未知,则返回空字符串.
(type属性判断用户的文件类型不太准确,用户会改变后缀名;size可以做大小限制判断)
二、HTML5 拖拽操作文件
H5拖拽操作之后会单开一篇另做介绍
下面会对H5拖拽操作文件进行简单的讲解
var dropbox = document.getElementById("dropbox");
var preview = document.getElementById("preview");
dropbox.addEventListener("dragenter", function(e){
e.stopPropagation();
e.preventDefault();
}, false);
dropbox.addEventListener("dragover", function(e){
e.stopPropagation();
e.preventDefault();
}, false);
dropbox.addEventListener("drop", function(e){
e.stopPropagation();
e.preventDefault();
var dt = e.dataTransfer;
var files = dt.files;//获取文件
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /^image\//;
if ( !imageType.test(file.type) ) {
continue;
}
// 填充选择的图片到展示区
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
preview.appendChild(img);
// 读取File对象中的内容
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(e) {
aImg.src = e.target.result;
};
})(img);
reader.readAsDataURL(file);
}
}, false);
Blob、File、DataURL(Base64)和BlobURL之间的闭环关系
讲到这里就有必要对这些概念展开介绍,也方便对整个前端文件处理生态有一个更全面的认识。
相信在工作中经常遇到,文件上传、图片压缩、文件下载、大文件断点续传,等等关于 js 来操作文件的需求。那么你真的了解文件类型之间的转换关系吗?如下:
-
Blob
-->File
-
File
-->DataURL(base64)
-
File
-->BlobURL
-
HTTPURL| DataURL | BlobURL
-->Blob
一、Blob类型
Blob
类型是 File
文件类型的父类,它表示一个不可变、原始数据的类文件对象
如何得到 blob
对象?
1. new Blob(array, options)
let hiBlob = new Blob([`Hi!`], { type: 'text/html' })
如上代码,就创建了一个 blob
对象,并声明了 text/html
类型 ,就像是创建一个 .html
文件。只不过它存在于浏览器的内存里。
2. fetch(url)
js 为我们提供了很多获取资源的 api,如:和
,
Fetch API
提供了一个获取资源的统一接口(包括跨域请求)
关于 fetch(url, options)
, url
参数支持格式有:
http、https
-
blobURL
: 比如通过URL.createObjectURL()
获得// blobURL 示例: blob:null/7025638d-c05f-4c75-87d6-470a427e9aa3
-
dataURL
: 如图片的 base64 格式,比如通过convasElement.toDataURL()
获得// dataURL(base64) 黑色 1 像素示例: data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=
fetch(url, options)
响应数据可被解析成:
-
res.arrayBuffer()
: 通用、固定长度的原始二进制数据缓冲区 -
res.blob()
:Blob
类型 -
res.formData()
: 表单数据类型 -
res.json()
:JSON
格式 -
res.text()
: 文本格式
这里主要关心 blob
类型转换,如下代码,用 fetch api 获取图片资源的 blob 对象,
当然也可以获取其它类型的资源。如:.txt
.html
等
// 获取图片的 blob 对象
// 通过 http、https 获取
fetch('http://eg.com/to/path/someImg.png')
.then(res => res.blob())
.then(blob => {
console.log('blob: ', blob)
})
3. canvasElement.toBlob(callback)
canvas 具有图像操作能力,支持将一个已有的图片作为图片源,来操作图像。
如下,通过 canvas 将图片资源转成 blob
对象
Tips:
如果图片没加载完,就调用
drawImage
,canvas 绘制将失败,所以我们简单封装了fetchImg
方法,确保图片资源加载完成后再开始绘制图片。-
由于 canvas 中的图片可能来自一些第三方网站。在不做处理的情况下,使用跨域的图片绘制时会污染画布,这是出于安全考虑。在“被污染”的画布中调用
toBlob()
toDataURL()
getImageData()
会抛出安全警告。解决方法:
let img = new Image() // 1. 增加 crossOrigin 属性,值为 anonymous // 含义:执行一个跨域请求,在请求头里加 origin 字段 // 2. 后端要返回 Access-Control-Allow-Origin 响应头来允许跨域 img.crossOrigin = 'anonymous' img.src = 'to/path'
本质就是解决跨域问题,也可以使用
nginx
做个代理来解决 blob
有slice(startIndex, endIndex)
方法,复制 blob 对象某片段,与 js 数组的slice
方法类似,文件的断点续传功能就是利用了该特性。
二、File类型
File
包含文件的相关信息,可以通过 js 来访问其内容
如何获取 file
对象?
1. new File(bits, name[, options])
// 1. 参数是字符串组成的数组
let hiFile = new File([`Hi gauseen!`], 'fileName', { type: 'text/html' })
// 2. blob 转 file 类型
let hiBlob = new Blob([`Hi gauseen!`], { type: 'text/html' })
let hiFile = new File([ hiBlob ], 'fileName', { type: 'text/html' })
如上代码,通过 File
构造函数,创建一个 file
对象,与上面的提到的 blob
类似。可以将 blob 转成 file 类型,这意味着上面获取的 blob,可以转成 file 类型。
2. inputElement.files
通过 `` 标签获取 file
对象
// input 上传文件时触发 change 事件
$('input').addEventListener('change', e => {
let file = e.target.files[0]
console.log('file: ', file)
})
3. DragEvent.dataTransfer.files
通过拖、放获取 file
对象
将文件拖放到这里~
4. canvasElement.mozGetAsFile()
注: 截止当前,该方法仅支持火狐浏览器
let file = canvasElement.mozGetAsFile('imgName')
三、DataURL(base64)
DataURL,前缀为 data:
协议的 URL,可以存储一些小型数据
语法:data:[][;base64],
如下,黑色 1 像素示例:
data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=
上面提到的 Blob
File
类型,如何“消费”它们呢?接着向下看
1. FileReader
允许 Web 应用程序异步读取存储在用户计算机上的文件(blob
或 file
)。
// 将 blob 或 file 转成 DataURL(base64) 形式
fileReader(someFile).then(base64 => {
console.log('base64: ', base64)
})
function fileReader (blob) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.onload = (e) => {
resolve(e.target.result)
}
reader.readAsDataURL(blob)
})
}
2. convasElement.toDataURL()
可以通过 canvas 图像处理能力,将图片转成 dataURL 形式。在上面 Blob 部分讲解中,代码已实现。