利用FileReader和FormData实现图片预览和上传(base64转二进制文件)
监听表单文件变化
文件表单的样式主要通过让它后面,通过别的DOM来美化它。
<input type="file">
input.on.('change', preview);
预览
预览使用 FileReader
对象来读:
function preview(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onloadend = function () {
// 图片的 base64 格式, 可以直接当成 img 的 src 属性值
var dataURL = reader.result;
var img = new Image();
img.src = dataURL;
// 插入到 DOM 中预览
// ...
};
reader.readAsDataURL(file); // 读出 base64
}
提交图片文件(二进制文件 非 base64)
base64 转 二进制文件
/**
* dataURL to blob, ref to https://gist.github.com/fupslot/5015897
* @param dataURI
* @returns {Blob}
*/
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: mimeString});
}
构造 FormData
填充二进制文件数据,通过 ajax
的方式进行提交:
var fd = new FormData();
var blob = dataURItoBlob(dataURL);
fd.append('file', blob);
$.ajax({
type: 'POST',
url: '/upload',
data: fd,
processData: false, // 不会将 data 参数序列化字符串
contentType: false, // 根据表单 input 提交的数据使用其默认的 contentType
xhr: function() {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
console.log('进度', percentComplete);
}
}, false);
return xhr;
}
}).success(function (res) {
// 拿到提交的结果
}).error(function (err) {
console.error(err);
});
注意:不要漏了指定 processData
和 contentType
为 false
。
压缩
业务中不需要前端不需要压缩,因为后端有更靠谱的压缩方案,但是前端其实也可以压缩,那就是用 canvas
把图画出适合的大小,然后上传。
主要流程:
- 在
new
出来的Image
对象,我们监听它的onload
事件 - 按照压缩比例,算出压缩后的图片尺寸
- 创建
canvas
,尺寸设置成上一步骤算出来的压缩后的图片尺寸 - 调用
drawImage
方法,把图片绘制到canvas
中 - 调用
canvas
的toDataURL
,取出base64
格式的数据 - 后续的传图步骤和上面的原图上传一样
var img = new Image();
img.onload = function () {
// 当图片宽度超过 400px 时, 就压缩成 400px, 高度按比例计算
// 压缩质量可以根据实际情况调整
var w = Math.min(400, img.width);
var h = img.height * (w / img.width);
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 设置 canvas 的宽度和高度
canvas.width = w;
canvas.height = h;
// 把图片绘制到 canvas 中
ctx.drawImage(img, 0, 0, w, h);
// 取出 base64 格式数据
var dataURL = canvas.toDataURL('image/png');
// ...
};
img.src = reader.result;
自己的 OneWord
客户端的上传组件就是这么做的: ow-image-uploader.vue
这样一看,好像除去业务逻辑的话,好像也没多少代码
具体思路:
select local file -> Blob -> DataUrl -> Canvas compress -> DataUrl -> Blob -> Upload file
一、input:file属性
属性值有以下几个比较常用:
accept:表示可以选择的文件MIME类型,多个MIME类型用英文逗号分开,常用的MIME类型见下表。
multiple:是否可以选择多个文件,多个文件时其value值为第一个文件的虚拟路径。
1、accept
只能选择png和gif图片
<input id="fileId1" type="file" accept="image/png,image/gif" name="file" />