vue+element ui中的圖片獲取與上傳 工作上接觸了一下圖片的處理,圖片的格式是文件流, 記錄如下。 請求圖片 請求圖片的時候,帶上 , 否則圖片顯示的可能是亂碼。 顯示圖片 圖片返回的是文件流的形式, 控制臺中顯示的是亂碼。 直接顯示二進位圖片會出錯,所以我們要進行處理。 顯示圖片中,要對 ...
vue+element-ui中的圖片獲取與上傳
工作上接觸了一下圖片的處理,圖片的格式是文件流, 記錄如下。
請求圖片
請求圖片的時候,帶上{ responseType: 'blob' }
, 否則圖片顯示的可能是亂碼。
axios
.post(url, parmas, { responseType: 'blob' })
.then(res => {
return Promise.resolve(res);
})
.catch(e => {
return Promise.reject(e);
});
顯示圖片
圖片返回的是文件流的形式, 控制臺中顯示的是亂碼。
直接顯示二進位圖片會出錯,所以我們要進行處理。
<!-- template中 -->
<img alt="logo" :src="imageUrl" @error="handleLoadError" />
/*------ script中------*/
let urlCreator = window.URL || window.webkitURL;
let imageUrl = urlCreator.createObjectURL(res);
this.imageUrl = imageUrl;
顯示圖片中,要對萬一圖片顯示不出來的情況進行處理。使用onerror
事件可以對載入圖片失敗的情況進行處理。
handleLoadError(e) {
const img = e.srcElement;
this.imageUrl = this.errorLoadImg; // 用載入失敗的圖片替代之
img.onerror = null; // 清除錯誤:如果錯誤時載入時顯示的圖片出錯,將會一直迴圈,所以我們必須清除掉錯誤,限制運行一次
}
上傳圖片:使用 element-ui 的 el-upload
自動上傳,一次傳一張圖片
<el-upload
action="uploadUrl"
:show-file-list="false"
:accept="'image/*'"
:headers="{token:$cookieStorage.token}"
:on-success="handleSuccess"
:on-error="handleError"
:before-upload="handleBeforeUpload"
:on-progress="handleProgress"
>
<el-button type="primary" size="medium">上傳圖片</el-button>
</el-upload>
<!--
action: 圖片上傳的地址
show-file-list: 是否顯示文件上傳列表
accept: 可接受的上傳類型,image/*為圖片
headers: 頭部信息
on-success: 上傳成功事件
on-error: 上傳失敗事件
before-upload: 上傳前處理事件,返回一個值,值為false將阻止上傳
on-progress: 上傳中事件
-->
/*----- 以下為常用處理代碼 ------*/
handleSuccess(response, file, fileList) {
this.$success("上傳成功");
},
handleError() {
this.$error("上傳失敗,請重新上傳圖片!");
},
handleBeforeUpload(file) {
const isImage = file.type.includes("image");
if (!isImage) {
this.$message.error("上傳文件類型必須是圖片!");
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
this.$message.error("上傳圖片大小不能超過 2MB!");
}
return isImage && isLt2M;
},
handleProgress(event, file, fileList) {
this.loading = true; // 上傳時執行loading事件
}
手動上傳,一次提交多個 el-upload 的圖片
要求:每個 picture area 限制選擇一張圖片,點擊確定後一起提交。
<el-upload
action="myUrl"
:on-change="(file,fileList)=>{handleChange(file,fileList,1)}"
:on-remove="(file,fileList)=>{handleRemove(file,fileList,1)}"
:auto-upload="false"
:file-list="fileList[0]"
ref="file1"
>
<el-button size="small">選擇圖片</el-button>
</el-upload>
<el-upload
action="myUrl"
:on-change="(file,fileList)=>{handleChange(file,fileList,2)}"
:on-remove="(file,fileList)=>{handleRemove(file,fileList,2)}"
:auto-upload="false"
:file-list="fileList[1]"
ref="file2"
>
<el-button size="small">選擇圖片</el-button>
</el-upload>
<el-upload
action="myUrl"
:on-change="(file,fileList)=>{handleChange(file,fileList,3)}"
:on-remove="(file,fileList)=>{handleRemove(file,fileList,3)}"
:auto-upload="false"
:file-list="fileList[2]"
ref="file3"
>
<el-button size="small">選擇圖片</el-button>
</el-upload>
<el-button @click="submitData">確認</el-button>
<!--
action:提交的地址,此處隨便寫一個,不寫會報錯
on-change: 圖片上傳到緩存中將被觸發
on-remove: 從緩存中刪除文件將被觸發
-->
data(){
fileList: [0,0,0], //緩存區文件
uploadFile:[[],[],[]] // 上傳用文件
},
handleChange(file, fileList, type) {
// 限制單張上傳,超過限制即覆蓋
if (fileList.length > 1) {
fileList.splice(0, 1);
}
// 校驗
const isLt2M = file.size / 1024 / 1024 < 5;
if (!isLt2M) {
this.$message.error("上傳圖片大小不能超過 5MB!");
this.removeUploadedFile(type); // 不符合要求刪除文件
return false;
}
const isImage = file.raw.type.includes("image");
if (!isImage) {
this.$message.error("上傳的格式必須是圖片!");
this.removeUploadedFile(type);
return false;
}
// 驗證通過之後,將緩存區文件存入上傳區文件中
this.formData.files[type] = file.raw;
},
// 從緩存區移除文件
removeUploadedFile(type) {
if (type === 0) {
this.$refs.file1.clearFiles();
}
if (type === 1) {
this.$refs.file2.clearFiles();
}
if (type === 2) {
this.$refs.file3.clearFiles();
}
}
// 刪除文件
handleRemove(file, fileList, type) {
// 刪除文件時要移除緩存區文件和上傳區文件
this.fileList[type] = 0;
this.uploadFile[type] = [];
},
// 上傳文件
submitData() {
// 校驗是否選擇文件
let fileNum = this.flatten(this.uploadFile).length;
if (fileNum === 0) {
this.$error("未選擇任何文件!");
return false;
}
// 使用formdata格式
let formData = new FormData();
if (this.formData.files[0]) {
formData.append("file1", this.formData.files[0]);
}
if (this.formData.files[1]) {
formData.append("file2", this.formData.files[1]);
}
if (this.formData.files[2]) {
formData.append("file2", this.formData.files[2]);
}
// 請求:在headers上務必加上content-Type,指定表單形式發送
axios
.post("uploadUrl", formData, {headers: { "Content-Type": "multipart/form-data" }})
.then(res => {
this.$success("上傳圖片成功!");
this.fileList = [0,0,0];
this.uploadFile =[[],[],[]];
})
.catch(e => {
console.log(e);
});
}
// 扁平化數組
flatten(arr) {
let res = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(this.flatten(arr[i]));
} else {
res.push(arr[i]);
}
}
return res;
}
圖片載入技術:預載入和懶載入
- 預載入:重點在"預",在用戶需要看到該圖片之前,就已經載入和請求到該圖片。
- 懶載入: 重點在"懶",儘可能少的載入圖片,只載入必需的圖片(用戶屏幕可視範圍內),目的是儘可能的減少請求數,減緩伺服器的壓力。
在vue中懶載入的組件有很多,比如vue-lazy-laod
和vue-clazy-load
瀏覽器阻塞
同一時間對伺服器的請求過多,將會造成瀏覽器阻塞。
瀏覽器預設對同一域下的資源,只保持一定的連接數,阻塞過多的連接,以提高訪問速度和解決阻塞問題。
對於請求圖片來說,有以下解決方法
- 使用雪碧圖:把所有圖片合成一張大圖。
- 延遲載入:只去請求可視區的圖片。
最後使用了延遲載入,對非可視區領域的圖片延遲載入,優先載入可視區圖片,減少圖片的請求數。
<img :src="imageUrl" ref="img">
// 方式一:延遲載入非可視區域
delayTime() {
let windowHeight = window.innerHeight;
let imgTop = this.$refs.img.getBoundingClientRect().top;
const isDelay = imgTop > windowHeight;
if (isDelay) {
return Math.random() * 2000 + 3000;
} else {
return Math.random() * 2000 + 500;
}
}
// 方法二:按順序依次延遲載入
delayTime() {
if (this.params.index) {
return Math.random() * 2000 + this.params.index * this.params.type * 500;
} else {
return 0;
}
}
setTimeout(() => {
// 圖片請求代碼
}, this.delayTime);
使用延時載入前的請求
使用延時載入後的請求
參考
[1] XMLHttpRequest Standard.The responseType attribute
[2] XMLHttpRequest.responseType | MDN
[3] 理解DOMString、Document、FormData、Blob、File、ArrayBuffer數據類型 « 張鑫旭-鑫空間-鑫生活
[4] FormData 對象的使用 | MDN
[5] 前端|載入的圖片太多或者太大怎麼辦(上) - u012496505的博客 - CSDN博客
[6] Lazy Loading Images and Video | Web Fundamentals | Google Developers
[7] An Introduction to Progressive Image Rendering
[8] 原生 JS 實現最簡單的圖片懶載入 - WEB前端 - 伯樂線上
2019/1/14 9:15:33