此前与人讨论到了html5中a的download属性,同时发现了下载跨域资源时无法指定或修改文件名称的问题
参考资料:MDN
废话不多说,直接进入主题
第一种
使用URL.createObjectURL()生成url。
使用fetch抓取图片数据,再用response.blob()生成blob对象,然后用URL.createObjectURL()生成指向blob的url地址给a
元素的href
使用。即可使资源变为本地资源,然后就能使用a
元素的download
属性指定文件名,或者在弹出的另存为中自行修改文件名。(对于URL.createObjectURL()
生成的url
关联的对象,可以看这里的概述部分。)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49<input id="url" type="text" placeholder="url."/>
<hr>
<a id="a">
<img id="preview" src="#"/>
</a>
<script>
const default_url = `http://img.hb.aicdn.com/53bb197860c1bd590288e4186ec95487c782543d26052-KeYrnF`
const img_id = 'downloadImg'
const url = document.getElementById("url")
const pimg = document.getElementById("preview")
url.focus()
url.value = default_url
// 加载默认图片
pimg.setAttribute("src", url.value)
url.addEventListener("blur", event => {
const src = url.value
// 加载指定图片
pimg.setAttribute("src", src)
download(src, `${img_id}`)
})
function download(url, name) {
name = name || url
// fetch抓取图片数据
fetch(url).then(response=> {
if( response.status == 200 )
// 返回的.blob()为promise,然后生成了blob对象,此方法获得的blob对象包含了数据类型,十分方便
return response.blob()
throw new Error(`status: ${response.status}.`)
}).then(blob=> {
// 获取到blob对象
downloadFile(name, blob)
}).catch(error=> {
console.log("failed. cause:", error)
})
}
// 点击图片即可下载
function downloadFile(fileName, blob) {
const anchor = document.getElementById("a")
// 创建指向blob对象地址
const src = URL.createObjectURL(blob)
anchor.download = fileName
anchor.href = src
}
</script>
注意:较新版本的Chrome,FireFox上可以下载,IE未实验
第二种
使用fileReader.addEventListener()生成dataUrl(base64编码)。
其他不变,只修改downloadFile部分代码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function downloadFile(fileName, blob) {
const anchor = document.getElementById("a")
const fileReader = new FileReader()
fileReader.addEventListener('load',()=>{
// 传入dataUrl地址
anchor.href = fileReader.result
},false)
fileReader.readAsDataURL(blob)
anchor.download = fileName
}
/* 也可以这样写
fileReader.addEventListener('load',(e)=>{
anchor.href = e.target.result
},false)
*/
注意:此方法兼容性较好,详细内容请查看MDN
第三种
使用canvas。
先用canvas载入,然后使用canvas的toDataUrl()。此方法对于跨域图片可能还有其他问题需要解决,网上文章很多,不深入讨论。且此方法加载的文件类型受限,故不推荐。
注意:此方法兼容性较好,详细内容请查看MDN
总结
以上都是使用fetch
先加载文件数据,但fetch
兼容性较差,有所顾忌可用XMLHttpRequest
代替(其实并不需要?)