[TOC]
* * * * *
### 一、图片上传的思路
1. 获取上传的图片,可以是通过 `<input type='file'>` 获取的也可以是通过拖放上传的图片
2. 通过canvas处理(压缩,旋转)图片
3. 将canvas处理后的图片转化为二进制
4. 通过`FormData() API`生成formdata 对象上传服务器
如果了解下边的api 则更加容易
- [ArrayBuffer处理二进制](https://www.kancloud.cn/webxiaoma/javascript/708943)
- [Blob处理类文件对象](https://www.kancloud.cn/webxiaoma/javascript/706859)
- [FileReader和FormData对象](https://www.kancloud.cn/webxiaoma/javascript/708944)
- [base64处理](https://www.kancloud.cn/webxiaoma/javascript/709983)
### 二、图片上传的实现
现在我们来编写处理上传图片的函数 `createImg`
```JavaScript
function createImg(file){ // 处理上传图片的函数
let reader = new FileReader();
reader.readAsDataURL(file); // 将接收到的图片以DataUrl格式读取为
reader.onload=() => { // 文件读取成功执行
let url = reader.result;
let image = new Image()
image.src = url;
image.onload = ()=>{ // 图片加载成功后执行
let canvasImg = document.createElement('canvas');
canvasImg.width = image.width
canvasImg.height = image.height
let ctx = canvasImg.getContext("2d")
ctx.drawImage(image, 0, 0,image.width,image.height);
let dataURL = canvasImg.toDataURL("image/jpeg",0.8); // 将canvas 转化为base64格式,并将canvas压缩0.8
let byteURL = atob(dataURL.split(',')[1]) // 解码base64
// 获取图片类型
let mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
// 将canvas 转为字节流
let buffer = new ArrayBuffer(byteURL.length);
let uintAry = new Uint8Array(buffer); //转化为8位无符号整数,长度1个字节
for (var i = 0; i < byteURL.length; i++) {
uintAry[i] = byteURL.charCodeAt(i);
// charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
}
let blob = new Blob([buffer],{type: mimeString})
let fd = new FormData();
fd.append("file", blob);
return fd;
}
}
}
```
接下来我们就需要上传图片了,有两种上传图片的方式,上面我们也提了
1. 通过input上传
```HTML
<input id="file" type="file" accept="image/*" >
<script>
let inp = document.getElementById('file')
inp.onchange = function(e){
let file = e.target.files[0]
createImg(file) // 上边处理图片的函数
}
</script>
```
2. 拖动上传
```HTML
<div id="uploadImg">
将图片拖拽到此区域
</div>
<img alt="拖动显示的图片"/>
<script>
let imgWrap = document.getElementById('uploadImg')
let img = document.querySelector('img')
imgWrap.ondragover = function(e){ // 拖动到放置框时触发(持续触发)
e.preventDefault();
}
imgWrap.ondrop = function(e){ // 进行放置时触发
e.preventDefault();
let files = e.dataTransfer.files
let fileType = files[0].type
if(!/^image\/(jpeg|png)/.test(fileType)){
console.log("上传的不是图片")
return false
}
let url = URL.createObjectURL(files[0]) // 生成Blob URL 展示缩略图
img.src = url
createImg(files) // 上边处理图片的函数
}
</script>
```
### 三、图片上传的一些注意点
#### 1. 调用手机相册或照相机
在移动端时调用手机相册我们可以使用
```HTML
<input type="file" accept="image/*" >
```
在移动端时调用手机相机我们可以使用
```HTML
<input type="file" accept="image/*" capture="camera">
```
#### 2. 苹果手机拍照后,上传的图片旋转了
这里是因为ios手机拍照时默认横屏拍照是0度,竖屏拍照图片会旋转90度,这里我们可以使用 [exif-js](https://github.com/exif-js/exif-js)
[推荐阅读](https://moxo.io/blog/2017/03/21/using-javascript-to-read-orientation-value-inside-jpeg-file/)
```JavaScript
import EXIF from 'exif-js'
let inp = document.getElementById('file')
inp.onchange = function(e){
let file = e.target.files[0]
EXIF.getData(file, function() {
let Orientation = EXIF.getTag(this, 'Orientation');
let roate;
if(Orientation != "" && Orientation != 1){
switch(Orientation){
case 6://需要顺时针(向左)90度旋转
roate = 90
break;
case 8://需要逆时针(向右)90度旋转
roate = -90
break;
case 3://需要180度旋转
roate = 180
break;
}
}
createImg(file,roate) // 上边处理图片的函数
});
}
```