1. 使用a標(biāo)簽的download屬性,下載所有類型文件:(Blob對(duì)象)
import axios from 'axios' //引入axios
export const download = (fileUrl, name)=> { // 下載文件地址和名稱
// console.log(fileUrl, name)
//一、直接下載
// window.location.href = fileUrl //在地址欄上出入U(xiǎn)RL即可觸發(fā)瀏覽器的下載功能(不符合需求)
// window.open(fileUrl) //同上,不符合需求
// 二、直接下載(使用a標(biāo)簽download屬性) (先將圖片轉(zhuǎn)成base64)
// var image = new Image()
// image.setAttribute('crossOrigin', 'anonymous')
// image.onload = function() {
// var canvas = document.createElement('canvas')
// canvas.width = image.width
// canvas.height = image.height
// var context = canvas.getContext('2d')
// context.drawImage(image, 0, 0, image.width, image.height)
// var url = canvas.toDataURL('image/png') // 得到圖片的base64編碼數(shù)據(jù)
// var a = document.createElement('a') // 生成一個(gè)a元素
// var event = new MouseEvent('click') // 創(chuàng)建一個(gè)單擊事件
// a.download = name || 'photo' // 設(shè)置圖片名稱
// a.href = url // 將生成的URL設(shè)置為a.href屬性
// a.dispatchEvent(event) // 觸發(fā)a的單擊事件
// }
// image.src = fileUrl
//三、使用a標(biāo)簽的download屬性,下載任意類型的文件、
// {注意:1.解決亂碼問(wèn)題,type指定文件類型
// 2.Blob([res.data]:傳入的是res.data;而不是res
// 3.responseType指定為blob對(duì)象}
axios({
method: "GET", // "POST"
url: fileUrl,
responseType: "blob", //【重點(diǎn):設(shè)置返回?cái)?shù)據(jù)類型,這里一定要設(shè)置,否則下載下來(lái)的文件會(huì)是空白】
}).then(res => {
downloadToFile(res,name)
//downloadFileByReader(res,name)
})
}
function downloadToFile(res,fileName){
var downloadUrl = window.URL.createObjectURL(new Blob([res.data],{type:res.data.type}))
var a = document.createElement('a')
a.style.display = 'none'
a.href = downloadUrl
a.download = fileName
//創(chuàng)建一個(gè)點(diǎn)擊事件,并傳遞給a
var event = new MouseEvent('click')
a.dispatchEvent(event)
}
// readAsDataURL() 方法會(huì)讀取指定的 Blob 或 File 對(duì)象。讀取操作為異步操作,當(dāng)讀取完成時(shí),
//可以從onload回調(diào)函數(shù)中通過(guò)實(shí)例對(duì)象的result屬性獲取data:URL格式的字符串(base64編碼),
// 此字符串即為讀取文件的內(nèi)容,可以放入a標(biāo)簽的href屬性中
function downloadFileByReader(res,fileName){
const reader = new FileReader()
// 傳入被讀取的blob對(duì)象
reader.readAsDataURL(res.data)
// 讀取完成的回調(diào)事件
reader.onload = (e) => {
let a = document.createElement('a')
a.download = fileName
a.style.display = 'none'
// 生成的base64編碼
let url = reader.result
a.href = url
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
}
注意問(wèn)題:
1.跨域圖片能正常裁剪(圖片未轉(zhuǎn)化成base64),應(yīng)該滿足三個(gè)條件:
- img元素中設(shè)置
crossorigin屬性 - 圖片允許跨域,設(shè)置響應(yīng)頭
Access-Control-Allow-Origin - 使用js方式請(qǐng)求圖片資源, 需要避免使用緩存,設(shè)置url后加上時(shí)間戳,或者h(yuǎn)ttp頭設(shè)置Cache-Control為no-cache
主要原因是:
- 如果使用跨域的資源畫(huà)到canvas中,并且資源沒(méi)有使用CORS去請(qǐng)求,canvas會(huì)被認(rèn)為是被污染了, canvas可以正常展示,但是沒(méi)辦法使用
toDataURL()或者toBlob()導(dǎo)出數(shù)據(jù),見(jiàn)Allowing cross-origin use of images and canvas。 所以通過(guò)在img標(biāo)簽上設(shè)置crossorigin,啟用CORS,屬性值為anonymous,在CORS請(qǐng)求時(shí)不會(huì)發(fā)送認(rèn)證信息,見(jiàn)HTML attribute: crossorigin。 - 在啟用CORS請(qǐng)求跨域資源時(shí),資源必須允許跨域,才能正常返回,最簡(jiǎn)單的方式設(shè)置響應(yīng)頭
Access-Control-Allow-Origin - 圖片已經(jīng)通過(guò)img標(biāo)簽加載過(guò),瀏覽器默認(rèn)會(huì)緩存下來(lái),下次使用js方式再去請(qǐng)求,直接返回緩存的圖片,如果緩存中的圖片不是通過(guò)CORS請(qǐng)求或者響應(yīng)頭中不存在
Access-Control-Allow-Origin,都會(huì)導(dǎo)致報(bào)錯(cuò)。
readAsDataURL 和 createObjectURL 對(duì)比
2. readAsDataURL (blob) 和 createObjectURL (blob) 的區(qū)別:
| readAsDataURL (blob) | createObjectURL (blob) | |
|---|---|---|
| 返回值 | 可以得到一段base64的字符串 | 得到的是當(dāng)前文件的一個(gè)內(nèi)存url |
| 內(nèi)存 | js垃圾回收機(jī)制自動(dòng)從內(nèi)存中清理 | 存在于當(dāng)前document內(nèi),清除方式通過(guò)revokeObjectURL()手動(dòng)清除 |
| 執(zhí)行方式 | 通過(guò)回調(diào)的方式f返回,異步執(zhí)行 | 直接返回,同步執(zhí)行 |
| 多個(gè)文件 | 同時(shí)處理多個(gè)文件時(shí),需要一個(gè)文件對(duì)應(yīng)一個(gè)FileReader對(duì)象 | 依次返回,沒(méi)有影響 |
| 優(yōu)勢(shì)對(duì)比 | 可直接轉(zhuǎn)為base64格式,直接用于業(yè)務(wù) | 得到本地內(nèi)存容器的URL地址,方便預(yù)覽,需要注意手動(dòng)釋放內(nèi)存的問(wèn)題,性能優(yōu)秀 |