mySkey - 前端下载文件的几种方式
盘点几种前端下载文件的方式,location.href,window.open,iframe,form表单,二进制流,a标签超链接。分别总结下不同的特点及优势。
location.href
location.href直接指向一个文件的话,浏览器会下载该文件。
对于单文件下载没有什么问题,但是如果下载多文件,点击过快就会重置掉前面的请求。
const download = (url) => {
window.location.href = url;
}
我选了这个
window.open
window.open可以打开一个新窗口,虽然能通过这种方式下载文件,但是新的窗口不会关闭,明显体验上不好:
const download = (url) => {
window.open(url);
}
iframe
iframe也可以向服务器发请求的,并且不会因为多次点击而重置之前的链接,可用于多文件下载:
const download = (url) => {
const iframe = document.createElement("iframe");
iframe.style.display = "none"; // 防止影响页面
iframe.style.height = 0; // 防止影响页面
iframe.src = url;
document.body.appendChild(iframe); // 这一行必须,iframe挂在到dom树上才会发请求
// 5分钟之后删除(onload方法对于下载链接不起作用,就先抠脚一下吧)
setTimeout(()=>{
iframe.remove();
}, 5 * 60 * 1000);
}
form表单
利用form表单提交能发起浏览器请求,并且也可以作为多文件下载来使用:
const download = (url) => {
var params = {// 参数
id:xx,
name:xx
};
var form = document.createElement('form')
form.id = 'form'
form.name = 'form'
document.body.appendChild (form)
for (var obj in params) {
if (params.hasOwnProperty(obj)) {
var input = document.createElement('input')
input.tpye='hidden'
input.name = obj;
input.value = params[obj]
form.appendChild(input)
}
}
form.method = "GET" //请求方式
form.action = url
form.submit()
document.body.removeChild(form)
}
二进制流
有时候后端返回是一个Blob的文件流形式,那么前端需要自己将文件流转成链接,然后下载:
const download = (content, fileName) => {
const blob = new Blob([content]);
const a = document.createElement("a");
const url = window.URL.createObjectURL(blob);
const filename = fileName;
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}
a标签
a标签及href指向的如果是一个下载链接,那么相当于下载文件,对于单文件下载还是ok的,不过快速点击几个下载按钮,有的下载会被Cancelled,这可不行:
const download = (url, fileName) => {
const a = document.createElement("a");
a.href = url;
a.download = fileName;
a.click();
}
form表单校验
function checkFormRules(rules, d) {
let result = false;
const ruleObj = {
required: (_, val) => !val,
len: (base, val) => base != val.length,
min: (base, val) => base > val.length,
max: (base, val) => base < val.length,
pattern: (base, val) => !base.test(val),
}
outer:
for (let i in rules) {
inter:
for (let j in rules[i]) {
const item = rules[i][j]
const itemKeys = Object.keys(item).filter(key => Object.keys(ruleObj).includes(key))
if (itemKeys.filter(key => ruleObj[key](item[key], d[i])).length>0) {
result = item['message']
break outer;
}
}
}
return result
}
lodash封装
const lodash = {}
const arrayExtend = {}
const stringExtend = {}
const objectExtend = {
get(obj, key, defaultValue) {
let result = obj;
for (let k of key.split('.')) {
if (result[k]) {
result = result[k]
} else {
result = false
break;
}
}
return result || defaultValue
}
}
const functionExtend = {}
const mathExtend = {}
const numberExtend = {}
const extendType = [
{
type: Array,
children: [
'join',
'concat'
],
extendFuns: arrayExtend
},
{
type: String,
children: [
'split',
'trim'
],
extendFuns: stringExtend
},
{
type: Object,
children: [
'assign'
],
extendFuns: objectExtend
},
{
type: Function,
children: [
'bind'
],
extendFuns: functionExtend
},
{
type: Math,
children: [
'min'
],
extendFuns: mathExtend
},
{
type: Number,
children: [
'toFixed'
],
extendFuns: numberExtend
},
]
extendType.forEach(item => {
const { children = [], extendFuns = {} } = item
for (let key of children) {
lodash[key] = (obj, ...args) => item.type.prototype[key].call(obj, ...args)
}
for (let key in extendFuns) {
lodash[key] = extendFuns[key]
}
})
console.log(lodash.get({user:{name: '55'}}, 'user.name'))
console.log(lodash.join([1, 2, 3], '-'))