项目中下载相关的需求比较多,下载的时候需要更改文件名称。这里有两种方法,一种是通过blob转换,通过a标签下载;另一种是通过插件streamSaver和fetch进行下载。

说下优缺点

  1. 方案一
  • a标签进行下载,如果不用更改文件名称,那就比较方便,并且不需要进行blob转换。但是如果是下载视频录像等,使用a标签就会先打开新的页面,在进行点击下载操作。操作流程比较长。
  • 如果使用a标签并且需要更改文件名称,就需要先进行blob转换操作,通过XMLHttpRequest进行转换,如果是视频类或者文件内容比较大的情况下,耗时长并且页面长时间无响应变化,可能造成用户多次触发下载操作。
  • 下载过程中无进度显示,转成blob之后秒下载,但是转的过程耗时长。

代码如下:

// 无需换名
function downloadFileByUrl(url) {var loadBtn = document.createElement('a');document.body.appendChild(loadBtn);loadBtn.setAttribute('href', url);// 如果是pdf格式,则打开新页面预览后下载if(url.indexOf('pdf')>-1) {loadBtn.setAttribute('target', '_blank');}loadBtn.setAttribute('download', '');loadBtn.click();document.body.removeChild(loadBtn)
}// 需要换名
function download(url, filename) {getBlob(url, function(blob) {saveAs(blob, filename);});
};
// 转blob
function getBlob(url,cb) {var xhr = new XMLHttpRequest();xhr.open('GET', url, true);xhr.responseType = 'blob';xhr.onload = function() {if (xhr.status === 200) {cb(xhr.response);}};xhr.send();
}function saveAs(blob, filename) {if (window.navigator.msSaveOrOpenBlob) {navigator.msSaveBlob(blob, filename);} else {var link = document.createElement('a');var body = document.querySelector('body');link.href = window.URL.createObjectURL(blob);link.download = filename;// fix Firefoxlink.style.display = 'none';body.appendChild(link);link.click();body.removeChild(link);window.URL.revokeObjectURL(link.href);};
}
  1. 方案2
  • 使用streamSaver进行下载,页面会显示当前下载进度及总共下载大小,页面空白等待时间短,用户能看到下载操作正在进行。

  • 缺点是 页面会有一个小弹框。
    总体来说使用streamSaver插件要比方案一体验更好。

代码如下

// 引入streamSaver
<script src="/js/streamSaver.js" type="text/javascript"></script>fetch(url, {method: 'GET',cache: 'no-cache'}).then(res=> {const fileStream = streamSaver.createWriteStream(name+'.mp4', {size : res.headers.get("content-length")})const readableStream = res.body// more optimizedif (window.WritableStream && readableStream.pipeTo) {return readableStream.pipeTo(fileStream).then(() => console.log('done writing'))}window.writer = fileStream.getWriter()const reader = res.body.getReader()const pump = () => reader.read().then(res => res.done? window.writer.close(): window.writer.write(res.value).then(pump))pump()})

streamSaver插件地址

streamSaver.js源码如下,github进不去的同学可以直接复制。

/* global chrome location ReadableStream define MessageChannel TransformStream */;((name, definition) => {typeof module !== 'undefined'? module.exports = definition(): typeof define === 'function' && typeof define.amd === 'object'? define(definition): this[name] = definition()
})('streamSaver', () => {'use strict'const global = typeof window === 'object' ? window : thisif (!global.HTMLElement) console.warn('streamsaver is meant to run on browsers main thread')let mitmTransporter = nulllet supportsTransferable = falseconst test = fn => { try { fn() } catch (e) {} }const ponyfill = global.WebStreamsPolyfill || {}const isSecureContext = global.isSecureContext// TODO: Must come up with a real detection test (#69)let useBlobFallback = /constructor/i.test(global.HTMLElement) || !!global.safari || !!global.WebKitPointconst downloadStrategy = isSecureContext || 'MozAppearance' in document.documentElement.style? 'iframe': 'navigate'const streamSaver = {createWriteStream,WritableStream: global.WritableStream || ponyfill.WritableStream,supported: true,version: { full: '2.0.5', major: 2, minor: 0, dot: 5 },mitm: 'https://jimmywarting.github.io/StreamSaver.js/mitm.html?version=2.0.0'}/*** create a hidden iframe and append it to the DOM (body)** @param  {string} src page to load* @return {HTMLIFrameElement} page to load*/function makeIframe (src) {if (!src) throw new Error('meh')const iframe = document.createElement('iframe')iframe.hidden = trueiframe.src = srciframe.loaded = falseiframe.name = 'iframe'iframe.isIframe = trueiframe.postMessage = (...args) => iframe.contentWindow.postMessage(...args)iframe.addEventListener('load', () => {iframe.loaded = true}, { once: true })document.body.appendChild(iframe)return iframe}/*** create a popup that simulates the basic things* of what a iframe can do** @param  {string} src page to load* @return {object}     iframe like object*/function makePopup (src) {const options = 'width=200,height=100'const delegate = document.createDocumentFragment()const popup = {frame: global.open(src, 'popup', options),loaded: false,isIframe: false,isPopup: true,remove () { popup.frame.close() },addEventListener (...args) { delegate.addEventListener(...args) },dispatchEvent (...args) { delegate.dispatchEvent(...args) },removeEventListener (...args) { delegate.removeEventListener(...args) },postMessage (...args) { popup.frame.postMessage(...args) }}const onReady = evt => {if (evt.source === popup.frame) {popup.loaded = trueglobal.removeEventListener('message', onReady)popup.dispatchEvent(new Event('load'))}}global.addEventListener('message', onReady)return popup}try {// We can't look for service worker since it may still work on httpnew Response(new ReadableStream())if (isSecureContext && !('serviceWorker' in navigator)) {useBlobFallback = true}} catch (err) {useBlobFallback = true}test(() => {// Transferable stream was first enabled in chrome v73 behind a flagconst { readable } = new TransformStream()const mc = new MessageChannel()mc.port1.postMessage(readable, [readable])mc.port1.close()mc.port2.close()supportsTransferable = true// Freeze TransformStream object (can only work with native)Object.defineProperty(streamSaver, 'TransformStream', {configurable: false,writable: false,value: TransformStream})})function loadTransporter () {if (!mitmTransporter) {mitmTransporter = isSecureContext? makeIframe(streamSaver.mitm): makePopup(streamSaver.mitm)}}/*** @param  {string} filename filename that should be used* @param  {object} options  [description]* @param  {number} size     deprecated* @return {WritableStream<Uint8Array>}*/function createWriteStream (filename, options, size) {let opts = {size: null,pathname: null,writableStrategy: undefined,readableStrategy: undefined}let bytesWritten = 0 // by streamSaver.js (not the service worker)let downloadUrl = nulllet channel = nulllet ts = null// normalize argumentsif (Number.isFinite(options)) {[ size, options ] = [ options, size ]console.warn('[StreamSaver] Deprecated pass an object as 2nd argument when creating a write stream')opts.size = sizeopts.writableStrategy = options} else if (options && options.highWaterMark) {console.warn('[StreamSaver] Deprecated pass an object as 2nd argument when creating a write stream')opts.size = sizeopts.writableStrategy = options} else {opts = options || {}}if (!useBlobFallback) {loadTransporter()channel = new MessageChannel()// Make filename RFC5987 compatiblefilename = encodeURIComponent(filename.replace(/\//g, ':')).replace(/['()]/g, escape).replace(/\*/g, '%2A')const response = {transferringReadable: supportsTransferable,pathname: opts.pathname || Math.random().toString().slice(-6) + '/' + filename,headers: {'Content-Type': 'application/octet-stream; charset=utf-8','Content-Disposition': "attachment; filename*=UTF-8''" + filename}}if (opts.size) {response.headers['Content-Length'] = opts.size}const args = [ response, '*', [ channel.port2 ] ]if (supportsTransferable) {const transformer = downloadStrategy === 'iframe' ? undefined : {// This transformer & flush method is only used by insecure context.transform (chunk, controller) {if (!(chunk instanceof Uint8Array)) {throw new TypeError('Can only write Uint8Arrays')}bytesWritten += chunk.lengthcontroller.enqueue(chunk)if (downloadUrl) {location.href = downloadUrldownloadUrl = null}},flush () {if (downloadUrl) {location.href = downloadUrl}}}ts = new streamSaver.TransformStream(transformer,opts.writableStrategy,opts.readableStrategy)const readableStream = ts.readablechannel.port1.postMessage({ readableStream }, [ readableStream ])}channel.port1.onmessage = evt => {// Service worker sent us a link that we should open.if (evt.data.download) {// Special treatment for popup...if (downloadStrategy === 'navigate') {mitmTransporter.remove()mitmTransporter = nullif (bytesWritten) {location.href = evt.data.download} else {downloadUrl = evt.data.download}} else {if (mitmTransporter.isPopup) {mitmTransporter.remove()mitmTransporter = null// Special case for firefox, they can keep sw alive with fetchif (downloadStrategy === 'iframe') {makeIframe(streamSaver.mitm)}}// We never remove this iframes b/c it can interrupt savingmakeIframe(evt.data.download)}}}if (mitmTransporter.loaded) {mitmTransporter.postMessage(...args)} else {mitmTransporter.addEventListener('load', () => {mitmTransporter.postMessage(...args)}, { once: true })}}let chunks = []return (!useBlobFallback && ts && ts.writable) || new streamSaver.WritableStream({write (chunk) {if (!(chunk instanceof Uint8Array)) {throw new TypeError('Can only write Uint8Arrays')}if (useBlobFallback) {// Safari... The new IE6// https://github.com/jimmywarting/StreamSaver.js/issues/69//// even though it has everything it fails to download anything// that comes from the service worker..!chunks.push(chunk)return}// is called when a new chunk of data is ready to be written// to the underlying sink. It can return a promise to signal// success or failure of the write operation. The stream// implementation guarantees that this method will be called// only after previous writes have succeeded, and never after// close or abort is called.// TODO: Kind of important that service worker respond back when// it has been written. Otherwise we can't handle backpressure// EDIT: Transferable streams solves this...channel.port1.postMessage(chunk)bytesWritten += chunk.lengthif (downloadUrl) {location.href = downloadUrldownloadUrl = null}},close () {if (useBlobFallback) {const blob = new Blob(chunks, { type: 'application/octet-stream; charset=utf-8' })const link = document.createElement('a')link.href = URL.createObjectURL(blob)link.download = filenamelink.click()} else {channel.port1.postMessage('end')}},abort () {chunks = []channel.port1.postMessage('abort')channel.port1.onmessage = nullchannel.port1.close()channel.port2.close()channel = null}}, opts.writableStrategy)}return streamSaver
})

js 浏览器下载显示进度相关推荐

  1. Android 多线程下载 显示进度 速度

    功能要求:从网络下载一APK应用,显示下载速度.进度,并安装应用. 运行效果图: 工程结构图: 很简单,就一个activity,一个更新UI的线程,一个下载线程加个文件处理类 主要代码: /***多线 ...

  2. js浏览器下载jpg, png, txt文件踩坑(尝试了百度的各种方法,以下总结2个靠谱点的)

    使用a标签下载jpg,png , txt 格式文件的话,因为浏览器机制的原因,会直接打开文件而不是下载!(如果是相对路径的文件,使用a标签的href则能正常下载) 网络图片jpg,png下载 例如le ...

  3. vue下载大文件时浏览器不显示下载进度

    vue下载大文件时浏览器不显示下载进度 问题描述 最近开发中遇到个问题,项目需要下载大文件(音视频),由于后端给我的是视频的地址而不是直接返回流,所以前端用了XMLHttpRequest获取视频流并实 ...

  4. 文件下载显示进度条以及调取浏览器下载进程

    最近遇见项目的文件下载功能 总结了两种获取文件下载进度的方法 1 .axios 在axios里可调取onUploadProgress方法来获取 通过判断是否存在lengthComutable来获取下载 ...

  5. 基于asp.net + easyui框架,js实现上传图片之前判断图片格式,同时实现预览,兼容各种浏览器+下载...

    2019独角兽企业重金招聘Python工程师标准>>> 最近在做图片上传的一个前台页面,上传图片功能虽然很简单,但是需要我们学习的地方很多.在上传图片之前验证图片的格式,并同时实现预 ...

  6. 浏览器中利用js打包下载所有类型文件

    浏览器中利用js打包下载所有类型文件 概述 ajax请求方式打包下载所有类型文件 canvas渲染方式打包下载所有图片 相关知识 作者 概述 需求:1.项目中在浏览器中点击按钮后根据多个url地址下载 ...

  7. java 下载文件 进度条_使用处理程序下载文件时显示百分比的进度条

    我想在按钮上单击下载 .EXE 文件并在网页上显示下载进度条而不是浏览器进度条 . 这个开发背后的想法是浏览器在他的下载管理器中隐藏它的下载进度条 . 我想在下载达到100%后自动运行.EXE . 我 ...

  8. 原生JS实现拖拽进度条、滚动鼠标显示相应的内容

    今天要分享的是运用原生JS实现拖拽进度条.滚动鼠标显示相应的内容,实现效果如下: 以下是代码实现,欢迎大家复制粘贴. <!DOCTYPE html> <html><hea ...

  9. 利用curl下载文件(进度条显示) 代码片段

    在项目中需要用到程序更新的功能,同事介绍说是curl中的开发库很不错,于是下载这个包测试了一下,确实不错.准备正式用到项目中,以下一个例子用于从互联网上抓取一个文件下载到本地,并加上进度条显示,做得挺 ...

  10. Android 下载文件并显示进度条

    2019独角兽企业重金招聘Python工程师标准>>> OK,上一篇文章讲了上传文件到服务端,并显示进度条 那么这边文章主要讲下载文件并显示进度条. 由于简单,所以只上传代码.还是需 ...

最新文章

  1. 都2020年,开发制作微信小程序商城,需要准备什么资料?应该不会不知道吧!
  2. 主板上来了一个新邻居,CPU 慌了!
  3. 二维指针动态分配内存连续问题分析
  4. SAP BW增量队列深入研究
  5. 51单片机的轮胎气压监测系统_SHT11传感器的温度、湿度采集系统,51单片机,Proteus仿真,C代码等...
  6. MVC学习之分页 【转】
  7. 利用STM32制作红外测温仪之软件设计(MLX90614)
  8. 反射实现方法调用(1):执行机制
  9. 【剑指 offer】(十九)—— 二叉树镜像
  10. 前端开发的模块化和组件化的定义,以及两者的关系?
  11. QT5.14.2+VS2017环境安装
  12. 2021-06-09使用IAR软件进行TMS470程序刷写说明
  13. MD5算法实战JS解密
  14. 企业管理--盖洛普Q12测评法
  15. Win10要是个人,也算是鬼门关走过一遭了 1
  16. 各个国家的人有什么特点?
  17. 示波器界面的中英文切换
  18. Python深度学习基础(二)——反向传递概念透彻解析以及Python手动实现
  19. 如何把项目部署到腾讯云服务器(附带常见错误)
  20. RAID 5配置方法(命令模式)详解

热门文章

  1. xpath无法定位tbody
  2. 多页pdf怎样合并成一页?
  3. oracle当天是这个月的第几周,oracle_oracle查看当前日期是第几个星期的方法,系统当前时间是多少周,就是 - phpStudy...
  4. 测试质量保障体系的建立
  5. 10月编程语言排行榜:Java第一无悬念,老戏骨重回前三!
  6. IReport导出PDF字体加粗失效
  7. html基础教程全集零基础入门到精通汇总整理(附详细的学习路线图)
  8. python 通达信公式函数_通达信,文华财经,非常实用的主图均线变色指标
  9. jclasslib插件_在IDEA利用断点debug+解析class文件+jclasslib插件
  10. Sql Server :Could not write value to key \Software\Classes\CLSID\...., Verify that you have....