前端实现下载的触发机制,一篇文章搞定下载(文件下载,图片下载,截屏下载)

本文主要是介绍前端实现下载的触发机制,一篇文章搞定下载(文件下载,图片下载,截屏下载),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 一、下载方式
        • 1.浏览器下载
        • 2.a标签触发下载
          • 什么是base64
          • 自定义下载文件名
      • 二、实战下载
        • 1.文件下载
        • 2.图片下载
        • 3.截屏下载(解决HTML2cavas截屏空白问题)

一、下载方式

一般来说,前端下载,一般分为利用浏览器下载,和a标签触发下载

1.浏览器下载

有时候我们会发现一张图片的路径如果直接输入在浏览器地址栏中就会直接触发下载

例如下面图片

http://webond.tpddns.cn:8823/facility/tempImage.json?path=upload/196afac1-3e44-47df-910b-8783a9807f00.png

但有些图片放入浏览器的地址栏却并没有触发下载,而是在也浏览器中出现图片预览效果

例如:

https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70

探求其原因,我们分别查看了2者了请求头

发现能触发下载的图片请求头存在该属性Content-Disposition: attachment

在这里插入图片描述

后端实现下载

浏览器下载,本质其实是后端在返回的响应头中添加

Content-Disposition:attachment; filename=’下载的文件名‘

那么只要是在浏览器地址栏中访问就能直接触发下载,

form表单下载

我们常用form表单,将下载的url在一个iframe中打开,来触发下载

2.a标签触发下载

对于上述这种存在下载头的url,使用a标签也能触发下载,(同样也是通过浏览器下载,如果没有下载头,a标签会预览该图片)

<a herf='url' download='下载的文件名' /> 

a标签触发下载,一种是上面的带下载头的,还有2种 dataUrl(base64), 和 blobUrl(流),这2种也能直接触发下载,也是用来实现纯前端下载的方式,如前端构建excel,截屏等,然后转换成blobUrl实现下载,对于base64想必大多数人都有疑惑,

什么是base64

基于64个可打印字符来表示二进制数据,在HTTP环境下传递较长的标识信息

简单说就是一串有内容的编码,例如在html中,使用base64的图片,将不会加载请求,因为这串编码就是这张图片,弊端就是浏览器也不会缓存这张图片,因为不是远程加载 的图片

如下:上传文件并转换为base64

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><input type="file" id='fileId'>
</body>
<script>// 上传图片转换成base64let upDOM = document.getElementById('fileId')upDOM.addEventListener('change', (e) => {console.log(e)console.log(upDOM.files[0])var reader = new FileReader();reader.readAsDataURL(upDOM.files[0]);reader.onload = function (ie) {var Base64Val = this.result;console.log('Base64')console.log(Base64Val)}})
</script>
</html>

通过上述例子,大家可以发现base64很长,所以当图片过大时,使用base64来下载,就会下载失败,因为超出了get的长度限制,所以,大部分情况下,不会直接使用base64,而是进一步转换为blobUrl文件流

// base64转换为blob流function  convertBase64UrlToBlob(base64) {var parts = base64.dataURL.split(";base64,");var contentType = parts[0].split(":")[1];var raw = window.atob(parts[1]);var rawLength = raw.length;var uInt8Array = new Uint8Array(rawLength);for (var i = 0; i < rawLength; i++) {uInt8Array[i] = raw.charCodeAt(i);}return new Blob([uInt8Array], {type: contentType});}
var blob = convertBase64UrlToBlob (base64)var blobUrl= URL.createObjectURL(blob);
自定义下载文件名

​ 一般情况下,下载的文件名字为后端定义好的文件名,或者是服务器存储的文件名,前端如果要修改,可以利用a标签的download 属性,自己定义下载的文件名,

<a herf='url' download='下载的文件名' />

但要注意一点,能使用download修改名字,要么是同源,要么只能是dataUrl 和bolbUrl,否则无法修改下载的名字

二、实战下载

1.文件下载

一般类似exsel这类下载文件,是需要给后台提交数据来下载的,一般也为post接口,对于这样的下载,

第一种方式使用表单提交 后台也需要接受的是formdata数据

如果页面有现有的表单

form表单下载

没有就用js创建一个隐形的form来提交表单

第二种方式还是使用ajax 后台接收正常的json即可

使用ajax是无法直接下载的,请求成功后,后台会返回一个文件流

看见会是这样的乱码但没什么影响的
在这里插入图片描述

request 为引入的封装好的axios

下面有几个点需要注意

1.是要定义响应的type ,responseType: “arraybuffer”,告诉服务器需要返回一个buffer,不然下载下来很可能 是乱码
在这里插入图片描述

2.我们需要在返回的header把名字取下来,

const fileName = res.headers['content-disposition'].split('=')[1]
//有时候,后端定义的fileName,无效,下载下来还是服务器存储的名字

​ 但是会发现明明header里面有就是取不到Content-Disposcition,

这个是响应头Access-Control-Expose-Headers规定的可以暴露给外部的header

MDN

默认情况下,只有七种 simple response headers (简单响应首部)可以暴露给外部:

  • Cache-Control
  • Content-Language
  • Content-Length
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

如果想要让客户端可以访问到其他的首部信息,可以将它们在 Access-Control-Expose-Headers 里面列出来。

所以后端只需要配置

response.setHeader("Access-Control-Expose-Headers","Content-Disposcition")

在这里插入图片描述

  function exportFile(url,data){request({//告诉服务器需要返回一个buffer,不然下载下来很可能		是乱码responseType: "arraybuffer",url: url,method: 'post',data: data}).then(res=>{const content = res.data//转换成blob对象const blob = new Blob([content],{ type: 'application/vnd.ms-excel;charset=utf-8' })//获取文件名字const fileName = res.headers['content-disposition'].split('=')[1]const elink = document.createElement('a')elink.download = decodeURI(fileName)elink.style.display = 'none'console.log(res);//生成blobUrlelink.href = URL.createObjectURL(blob)document.body.appendChild(elink)elink.click()URL.revokeObjectURL(elink.href) // 释放URL 对象document.body.removeChild(elink)})}
2.图片下载

如果是图片流,下载方式同上

但大多数时候,是使用一个url来下载

a href="http://webond.tpddns.cn:8823/facility/tempImage.json?path=upload/196afac1-3e44-47df-910b-8783a9807f00.png" download="修改的名字.png">点击</a>

上面提到过 需要后端设置下载头才能触发,但是因为不是同源无法修改名字

image-20210527152922083

但如果想自定义名字,同时也不需要后端设置下载头呢

这个时候我们就需要利用cavas转换一下,

tips注意 cavas,必须要跨越的图片,否则画出来就是空白,同时后台需要设置跨越 指定域名或者*,不然会报跨越的错误,同时图片也无法加载

image-20210527153736217

img.crossOrigin = "Anonymous";  //设置图片跨越,没有跨越cavas会被污染无法画出
     // 转换为base64function    convertUrlToBase64(url) {return new Promise(function (resolve, reject) {var img = new Image();//设置图片跨越,没有跨越cavas会被污染无法画出img.crossOrigin = "Anonymous";img.src = url;img.onload = function () {var canvas = document.createElement("canvas");canvas.width = img.width;canvas.height = img.height;var ctx = canvas.getContext("2d");ctx.drawImage(img, 0, 0, img.width, img.height);var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();//转换为base64var dataURL = canvas.toDataURL("image/" + ext);var base64 = {dataURL: dataURL,type: "image/" + ext,ext: ext};resolve(base64);};});}
   // base64转换为blob流function    convertBase64UrlToBlob(base64) {var parts = base64.dataURL.split(";base64,");var contentType = parts[0].split(":")[1];var raw = window.atob(parts[1]);var rawLength = raw.length;var uInt8Array = new Uint8Array(rawLength);for (var i = 0; i < rawLength; i++) {uInt8Array[i] = raw.charCodeAt(i);}return new Blob([uInt8Array], {type: contentType});}
  // 判断浏览器function  myBrowser() {var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串if (userAgent.indexOf("OPR") > -1) {return "Opera";} //判断是否Opera浏览器 OPR/43.0.2442.991if (userAgent.indexOf("Firefox") > -1) {return "FF";} //判断是否Firefox浏览器  Firefox/51.0if (userAgent.indexOf("Trident") > -1) {return "IE";} //判断是否IE浏览器 Trident/7.0; rv:11.0if (userAgent.indexOf("Edge") > -1) {return "Edge";} //判断是否Edge浏览器 Edge/14.14393if (userAgent.indexOf("Chrome") > -1) {return "Chrome";} // Chrome/56.0.2924.87if (userAgent.indexOf("Safari") > -1) {return "Safari";} //判断是否Safari浏览器 AppleWebKit/534.57.2 Version/5.1.7 Safari/534.57.2}

下载图片

 var url = 'https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70'var that = thisvar fileName = '自定义的名字'convertUrlToBase64(url).then(function (base64) {console.log(base64);// 图片转为base64returnvar blob = that.convertBase64UrlToBlob(base64); // 转为blob对象// 下载if (that.myBrowser() == "IE") {window.navigator.msSaveBlob(blob, fileName + ".png");} else if (that.myBrowser() == "FF") {window.location.href = url;} else {var a = document.createElement("a");a.download = fileName;a.href = URL.createObjectURL(blob);document.body.appendChild(a)a.click();URL.revokeObjectURL(a.href) // 释放URL 对象document.body.removeChild(a)}});

将上面几个代码和在一起就是完整的转换下载

3.截屏下载(解决HTML2cavas截屏空白问题)

有些时候,我们需要对图片进行处理拼接等,这个时候需要用到截屏,我们可以使用插件html2cavas,来做到截屏效果

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.js"></script><style>#content {background: red;display: flex;justify-content: center;align-items: center;width: 500px;height: 500px;}#capture{margin-left: 20px;width: 500px;height: 500px;}div{float: left;}img {width: 90%;height: auto;}</style>
</head><body><div id="content"><img src="https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70"alt=""></div><div id="capture"><p>截屏的图</p></div><button onclick="capture()">截屏</button>
</body></html>
<script>function capture(data) {const el = document.getElementById('content')html2canvas(el).then(canvas => {const imgUrl = canvas.toDataURL("image/png"); // 获取生成的图片的url console.log('imgUrl');console.log(imgUrl);var img = new Image();img.src = imgUrl;document.getElementById('capture').appendChild(img)})}
</script>

在这里插入图片描述

但是发现并没有把图片截取下来,原因就是上面说的图片没跨域无法在cavas上展现

我们需要3点配置,

1.图片上设置跨域crossorigin=“anonymous”

<img crossorigin="anonymous" src=''/>

2.html2cavas 跨域useCORS:true

html2canvas(el,{useCORS:true})

3.后台配置跨域头
在这里插入图片描述

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.js"></script><style>#content {background: red;display: flex;justify-content: center;align-items: center;width: 500px;height: 500px;}#capture {margin-left: 20px;width: 500px;height: 500px;}div {float: left;}img {width: 90%;height: auto;}</style>
</head><body><div id="content"><!--  crossorigin="anonymous" 配置图片跨域 --><img crossorigin="anonymous" src="https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70"alt=""></div><div id="capture"><p>截屏的图</p></div><button onclick="capture()">截屏</button>
</body></html>
<script>function capture(data) {const el = document.getElementById('content')// useCORS 配置html2canvas跨越html2canvas(el,{useCORS:true}).then(canvas => {const imgUrl = canvas.toDataURL("image/png"); // 获取生成的图片的url console.log('imgUrl');console.log(imgUrl);var img = new Image();img.src = imgUrl;document.getElementById('capture').appendChild(img)})}
</script>

在这里插入图片描述

如果觉得默认截图过小,或者需要其他配置参考文档配置

html2cavas

下面就是完整截屏下载代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.js"></script><style>#content {background: red;display: flex;justify-content: center;align-items: center;width: 500px;height: 500px;}#capture {margin-left: 20px;width: 500px;height: 500px;}div {float: left;}img {width: 90%;height: auto;}</style>
</head><body><div id="content"><!--  crossorigin="anonymous" 配置图片跨域 --><img crossorigin="anonymous"src="https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70"alt=""></div><div id="capture"><p>截屏的图</p></div><button onclick="capture()">截屏</button>
</body></html>
<script>var that = thisfunction capture(data) {const el = document.getElementById('content')// useCORS 配置html2canvas跨越html2canvas(el, {useCORS: true}).then(canvas => {const imgUrl = canvas.toDataURL("image/png"); // 获取生成的图片的url console.log('imgUrl');console.log(imgUrl);var img = new Image();img.src = imgUrl;document.getElementById('capture').appendChild(img)var blob = this.convertBase64UrlToBlob(imgUrl)const name = '捕获的图片.png'var a = document.createElement("a");a.download = decodeURI(name);a.href = URL.createObjectURL(blob);document.body.appendChild(a)a.click();URL.revokeObjectURL(a.href) // 释放URL 对象document.body.removeChild(a)})}// 转换成blob对象function convertBase64UrlToBlob(base64) {var parts = base64.split(";base64,");var contentType = parts[0].split(":")[1];var raw = window.atob(parts[1]);var rawLength = raw.length;var uInt8Array = new Uint8Array(rawLength);for (var i = 0; i < rawLength; i++) {uInt8Array[i] = raw.charCodeAt(i);}return new Blob([uInt8Array], {type: contentType});}
</script>

这篇关于前端实现下载的触发机制,一篇文章搞定下载(文件下载,图片下载,截屏下载)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/641946

相关文章

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg