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 = urlform.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 = falsebreak;}}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 = {} } = itemfor (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], '-'))
