--- title: 完美的兼容性好的前端文件下载方式探讨 date: 2022/3/29 10:42:20 tags: - 前端 - 文件下载 - JavaScript author: 李燕 --- 在项目中,经常会遇到文件下载的需求。一开始,都是copy既有项目的下载方法,用于自己的项目。但是,渐渐发现,copy过来的方法,有时会出现这样那样的问题,而且不同的项目,用的方法又是不一样的,没有一个通用的方法。 故感觉自己在文件下载这块,思绪还是乱的,没有一个清晰且系统概念。所以想通过本篇文章,好好地整理一下。 <!-- more --> 我们下载的文件,通常有三种形式: - 有明确地址路径的文件 - 二进制数据文件 - base64文件 而根据浏览器的特性,又可以分为: - 浏览器可直接浏览的文件,如txt、png、jpg、gif等格式的文件 - 浏览器不能直接浏览的文件,如doc、excel、zip等格式的文件 在下载方式这块,针对不同文件类型,常用的方式也不同。 **一、对于有明确地址路径的文件进行下载** 1. window API 实现下载 ```js window.open(fileUrl) window.location.href = fileUrl ``` 这两种方式虽然简单方便直接,但是浏览器能直接打开的文件只能预览,不能下载。 2. form表单实现下载 ```js const fromObj = document.createElement('form') fromObj.action = fileUrl formObj.method = 'get' formObj.style.display = 'none' const formItem = document.createElement('input') formItem.value = fileName formItem.name = 'fileName' formObj.appendChild(formItem) document.body.appendChild(formObj) formObj.submit() document.body.removeChild(formObj) ``` 这是以前常用的传统方式,利用表单提交的功能来实现文件的下载。兼容性好,但是也无法下载浏览器能直接预览的文件。 3. a标签实现下载 ```js <a href="fileUrl"></a> ``` 如果仅仅这样写,对于浏览器能直接打开的文件也是只能预览,不能下载。 要想能够直接下载浏览器能直接打开的文件,可以利用download属性。 ```js <a href="fileUrl" download="fileName"></a> ``` 但download属性实现浏览器可预览文件下载也有限制: - 同源,即所要下载的文件与当前页面同源。 - 非IE浏览器。 也就是说,如果不同源或是IE浏览器,即使加了download属性,也不能实现浏览器可预览文件的下载。 **二、对于二进制数据文件进行下载** ``` downFile(params).then(res=> { const fileName = res.headers['content-disposition'].split('=')[1]; const data = res.data; const blob = new Blob([data]); //如果浏览器不支持download属性(也就是使用IE10及以上的时候,使用msSaveOrOpenBlob方法,但IE10以下也不支持msSaveOrOpenBlob if(window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveOrOpenBlob(blob, fileName ) return } // const a = document.createElement('a'); const href = window.URL.createObjectURL(blob); // 创建下载的链接 a.href = href; a.download = decodeURI(fileName); // 下载后文件名 document.body.appendChild(a); a.click(); // 点击下载 document.body.removeChild(a); // 下载完成移除元素 window.URL.revokeObjectURL(href); // 释放掉blob对象 ``` 这种方式主要将文件流转换成Blob对象,并利用URL.createObjectURL生成url地址,然后再利用a标签下载。 但这种同样存在兼容性问题,IE10以下不可用。 **三、对于base64文件进行下载** ```js downFile(fileBase64) { // fileBase64是获取到的图片base64编码 const imgUrl = `data:image/png;base64,${fileBase64}` if (window.navigator.msSaveOrOpenBlob) { const bstr = atob(imgUrl.split(',')[1]) let n = bstr.length const u8arr = new Uint8Array(n) while (n--) { u8arr[n] = bstr.charCodeAt(n) } const blob = new Blob([u8arr]) window.navigator.msSaveOrOpenBlob(blob, fileName + '.' + 'png') } else { const a = document.createElement('a') a.href = imgUrl a.setAttribute('download', fileName) a.click() } } ``` IE10以下的兼容性问题依然存在。 以上文件下载方式,或多或少都存在一些限制或兼容性问题,有没有完美的解决方案,欢迎大佬们指教!