[TOC]
* * * * *
### 一、圖片上傳的思路
1. 獲取上傳的圖片,可以是通過 `<input type='file'>` 獲取的也可以是通過拖放上傳的圖片
2. 通過canvas處理(壓縮,旋轉)圖片
3. 將canvas處理后的圖片轉化為二進制
4. 通過`FormData() API`生成formdata 對象上傳服務器
如果了解下邊的api 則更加容易
- [ArrayBuffer處理二進制](http://www.hmoore.net/webxiaoma/javascript/708943)
- [Blob處理類文件對象](http://www.hmoore.net/webxiaoma/javascript/706859)
- [FileReader和FormData對象](http://www.hmoore.net/webxiaoma/javascript/708944)
- [base64處理](http://www.hmoore.net/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) // 上邊處理圖片的函數
});
}
```