├── .babelrc ├── .editorconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── README.md ├── example ├── README.md ├── package.json ├── public │ └── index.html └── src │ └── index.js ├── package.json ├── rollup.config.js └── src ├── base64ToFileOrBlob.js ├── index.js ├── saveFileToBlob.js ├── saveFileToLink.js └── utils.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react"], 3 | "env": { 4 | "production": { 5 | "presets": ["es2015-rollup"] 6 | }, 7 | "test": { 8 | "presets": ["es2015"], 9 | "plugins": ["istanbul"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig help us maintain consistent coding style between different editors. 2 | # 3 | # EditorConfig 4 | # http://editorconfig.org 5 | # 6 | root = true 7 | 8 | [*] 9 | indent_style = space 10 | indent_size = 2 11 | end_of_line = lf 12 | charset = utf-8 13 | trim_trailing_whitespace = true 14 | insert_final_newline = true 15 | 16 | [*.md] 17 | trim_trailing_whitespace = false 18 | 19 | [Makefile] 20 | indent_style = tab 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .nyc_output/ 4 | coverage/ 5 | package-lock.json 6 | dist 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | example 3 | *.log 4 | 5 | # don't ignore .npmignore files 6 | !.npmignore 7 | src 8 | rollup.config.js -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.0" 4 | - "6.0" 5 | before_install: 6 | - curl -o- -L https://yarnpkg.com/install.sh | bash 7 | - export PATH="$HOME/.yarn/bin:$PATH" 8 | script: "npm test" 9 | after_success: "npm run report-coverage" 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # web-downloadfile 2 | 3 | 文件下载 [web-downloadfile](https://github.com/jiang-jackson/web-downloadfile) 4 | 5 | ## BlogAddress 6 | 7 | [纯前端下载文件](https://www.cnblogs.com/jackson-yqj/p/11321275.html) 8 | 9 | ## Installation 10 | 11 | ```sh 12 | $ npm install web-downloadfile --save 13 | # or 14 | $ yarn add web-downloadfile 15 | ``` 16 | 17 | ## Usage 18 | 19 | ```jsx 20 | import { base64ToFileOrBlob, saveFileToBlob, saveFileToLink } from 'web-downloadfile'; 21 | ``` 22 | 23 | ### 一,base64ToFileOrBlob 24 | 25 | 主要针对图片 base64转blob对象 或 直接下载文件 但是文件也可用 26 | 27 | ```jsx 28 | import { base64ToFileOrBlob } from 'web-downloadfile'; 29 | 30 | let Blob = base64ToFileOrBlob(base64,'',true); 31 | 32 | // or 33 | 34 | base64ToFileOrBlob(base64,'',false); 35 | ``` 36 | 37 | ### 二,saveFileToBlob 38 | 39 | 主要用于文件导出下载 支持大部分文件类型 但是文件类型必传 40 | 41 | ```jsx 42 | import { saveFileToBlob } from 'web-downloadfile'; 43 | 44 | saveFileToBlob(Blob,'test','xlsx'); 45 | ``` 46 | 47 | ### 三,saveFileToLink 48 | 49 | 主要pdf文件链接的下载 因为pdf文件链接在浏览器会直接打开 但是其他文件的链接也可以下载 可监听文件下载进度 50 | 51 | link必须允许跨越访问 否则无法下载 52 | ```jsx 53 | import { saveFileToLink } from 'web-downloadfile'; 54 | 55 | saveFileToLink(link,'test','jpg',fn); 56 | ``` 57 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # web-downloadfile usage example 2 | 3 | Install dependencies and start the example: 4 | 5 | ```sh 6 | npm install 7 | npm start 8 | ``` 9 | 10 | Open http://localhost:3000 to view it in the browser. 11 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-downloadfile-usage-examples", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "web-downloadfile": "^0.0.1", 7 | "katex": "^0.10.0", 8 | "react": "^16.2.0", 9 | "react-dom": "^16.2.0", 10 | "react-katex-yingqi": "0.0.2", 11 | "react-scripts": "1.1.0" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | web-downloadfile usage examples 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import 'katex/dist/katex.min.css'; 5 | import { InlineMath } from 'react-katex-yingqi'; 6 | import { base64ToFileOrBlob, saveFileToBlob, saveFileToLink } from 'web-downloadfile'; 7 | class ExamplePage extends React.Component { 8 | constructor() { 9 | super(...arguments); 10 | this.state = { 11 | 12 | }; 13 | } 14 | 15 | /** 16 | * blob对象转base64 17 | * @param blob :blob对象 18 | * @param callback :回调函数 19 | */ 20 | blobToDataURL = (blob, callback) => { 21 | let a = new FileReader(); 22 | a.onload = function (e) { callback(e.target.result); } 23 | a.readAsDataURL(blob); 24 | } 25 | 26 | /** 27 | * base64转文件下载 28 | */ 29 | base64ToFile = () => { 30 | const deal = (base64) => { 31 | console.log('base64====', base64); 32 | base64ToFileOrBlob(base64, '', false); 33 | } 34 | var file = window.$("#file")[0].files[0]; 35 | if (file) { 36 | this.blobToDataURL(file, deal); 37 | } else { 38 | alert('请上传文件') 39 | } 40 | } 41 | 42 | /** 43 | * base64转blob对象 44 | */ 45 | base64ToBlob = () => { 46 | const deal = (base64) => { 47 | console.log('base64====', base64); 48 | let bolb = base64ToFileOrBlob(base64, '', true); 49 | console.log('bolb====', bolb); 50 | } 51 | var file = window.$("#file")[0].files[0]; 52 | if (file) { 53 | this.blobToDataURL(file, deal); 54 | } else { 55 | alert('请上传文件') 56 | } 57 | } 58 | 59 | /** 60 | * blob对象文件下载 61 | */ 62 | saveBlobToFile = () => { 63 | var blob = window.$("#file")[0].files[0]; 64 | if (blob) { 65 | saveFileToBlob(blob, 'test', 'jpg'); 66 | } else { 67 | alert('请上传文件') 68 | } 69 | } 70 | 71 | /** 72 | * 下载网络文件 73 | */ 74 | saveLinkToFile = () => { 75 | const onProgress = (progress) => { 76 | console.log('progress====', progress); 77 | } 78 | saveFileToLink('http://pic1.win4000.com/wallpaper/a/55349fb752abc.jpg', 'test', 'png', onProgress); 79 | } 80 | 81 | render() { 82 | return ( 83 |
89 |

90 | 91 | {'\\text{jqy-}\saveFile \\space \\text{usage examples}'} 92 | 93 |

94 |
95 | 96 | 97 |
98 |

99 | {` import { base64ToFileOrBlob } from 'web-downloadfile'; 100 | 101 | let Blob = base64ToFileOrBlob(base64,'image/png',true); 102 | 103 | // or 104 | 105 | base64ToFileOrBlob(base64,'image/png',false);`} 106 |

107 | 108 |
109 | 110 | 111 | 112 |

113 | {` import { saveFileToBlob } from 'web-downloadfile'; 114 | 115 | saveFileToBlob(Blob,'test','xlsx');`} 116 |

117 | 118 | 119 |

120 | {` import { saveFileToLink } from 'web-downloadfile'; 121 | 122 | saveFileToLink('http://pic1.win4000.com/wallpaper/a/55349fb752abc.jpg','test','jpg',fn);`} 123 |

124 | 125 |
126 | ); 127 | } 128 | } 129 | 130 | ReactDOM.render(, document.getElementById('root')); 131 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-downloadfile", 3 | "version": "0.0.1", 4 | "description": "File saving and picture conversion,forked from https://github.com/jiang-jackson/web-downloadfile", 5 | "keywords": [ 6 | "file", 7 | "base64", 8 | "blob", 9 | "link", 10 | "web", 11 | "download" 12 | ], 13 | "homepage": "https://github.com/jiang-jackson/web-downloadfile", 14 | "main": "dist/web-downloadfile.js", 15 | "scripts": { 16 | "build": "npm run build-normal && npm run build-mini", 17 | "build-normal": "rollup -c --environment NODE_ENV:production", 18 | "build-mini": "rollup -c --environment MINIFY,NODE_ENV:production", 19 | "test": "cross-env NODE_ENV=test nyc --reporter=html mocha", 20 | "report-coverage": "nyc report --reporter=text-lcov | coveralls", 21 | "lint": "eslint {src,test}/*.js", 22 | "prepublish": "npm run build" 23 | }, 24 | "author": { 25 | "name": "jackson", 26 | "email": "1591631526@qq.com", 27 | "url": "https:www.yingqigroup.top" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/jiang-jackson/web-downloadfile.git" 32 | }, 33 | "bugs": { 34 | "url": "https://github.com/jiang-jackson/web-downloadfile/issues" 35 | }, 36 | "license": "MIT", 37 | "devDependencies": { 38 | "babel-core": "^6.25.0", 39 | "babel-eslint": "^7.2.3", 40 | "babel-plugin-istanbul": "^4.1.4", 41 | "babel-preset-es2015": "^6.24.1", 42 | "babel-preset-es2015-rollup": "^3.0.0", 43 | "babel-preset-react": "^6.24.1", 44 | "coveralls": "^2.13.1", 45 | "cross-env": "^5.0.1", 46 | "mocha": "^3.4.2", 47 | "nyc": "^11.0.3", 48 | "rollup": "^0.43.0", 49 | "rollup-plugin-babel": "^2.7.1", 50 | "rollup-plugin-uglify": "^2.0.1" 51 | }, 52 | "nyc": { 53 | "sourceMap": false, 54 | "instrument": false 55 | }, 56 | "dependencies": { 57 | "is-blob": "^1.0.0", 58 | "moment": "^2.24.0" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import uglify from 'rollup-plugin-uglify'; 3 | 4 | const minify = !!process.env.MINIFY; 5 | 6 | const plugins = [babel()]; 7 | let dest = 'dist/web-downloadfile.js'; 8 | 9 | if(minify) { 10 | dest = 'dist/web-downloadfile.min.js'; 11 | plugins.push(uglify()); 12 | } 13 | 14 | export default { 15 | entry: 'src/index.js', 16 | format: 'umd', 17 | dest, 18 | plugins, 19 | moduleName: 'jqySaveFile' 20 | }; 21 | -------------------------------------------------------------------------------- /src/base64ToFileOrBlob.js: -------------------------------------------------------------------------------- 1 | import { isBase64 } from './utils'; 2 | import saveFileToBlob from './saveFileToBlob'; 3 | /** 4 | * 下载base64对象文件 5 | * @param urlData :数据的base64对象 6 | * @param type :类型 image/png; 7 | * @param isToBlob :是否转换Blob对象 并返回 默认true 8 | * @returns {Blob}:Blob文件对象 9 | */ 10 | export default function base64ToFileOrBlob(urlData, type, isToBlob = true) { 11 | if (isBase64(urlData)) {//判断是否是Base64字符串 12 | let arr = urlData.split(','); 13 | let array = arr[0].match(/:(.*?);/) 14 | let mime = (array && array.length > 1 ? array[1] : type) || type; 15 | // 去掉url的头,并转化为byte 16 | let bytes = window.atob(arr[1]); 17 | // 处理异常,将ascii码小于0的转换为大于0 18 | let ab = new ArrayBuffer(bytes.length); 19 | // 生成视图(直接针对内存):8位无符号整数,长度1个字节 20 | let ia = new Uint8Array(ab); 21 | for (let i = 0; i < bytes.length; i++) { 22 | ia[i] = bytes.charCodeAt(i); 23 | } 24 | let blob = new Blob([ab], { 25 | type: mime 26 | }); 27 | if (!!isToBlob) { 28 | return blob 29 | } else { 30 | //切割 31 | let arrType = mime.split("/"); 32 | let filetype = arrType[(arrType.length - 1)];//文件类型 33 | saveFileToBlob(blob, '', filetype) 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { default as base64ToFileOrBlob } from './base64ToFileOrBlob'; 2 | export { default as saveFileToBlob } from './saveFileToBlob'; 3 | export { default as saveFileToLink } from './saveFileToLink'; 4 | -------------------------------------------------------------------------------- /src/saveFileToBlob.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | import isBlob from 'is-blob'; 3 | /** 4 | *下载或导出文件 5 | * @param blob :返回数据的blob对象 6 | * @param tagFileName :下载后文件名标记 7 | * @param fileType :文件类 word(docx) excel(xlsx) ppt等 8 | */ 9 | export default function saveFileToBlob(blob, tagFileName, fileType) { 10 | if (fileType) { 11 | console.warn('未传入文件类型,例如文件类 word(docx) excel(xlsx) ppt jpg png等') 12 | } 13 | if (isBlob(blob)) { 14 | var downloadElement = document.createElement('a'); 15 | let href = window.URL.createObjectURL(blob); //创建下载的链接 16 | downloadElement.href = href; 17 | downloadElement.download = (tagFileName ? tagFileName : moment(new Date().getTime()).format('YYYYMMDDhhmmss')) + '.' + fileType; //下载后文件名 18 | document.body.appendChild(downloadElement); 19 | downloadElement.click(); //点击下载 20 | document.body.removeChild(downloadElement); //下载完成移除元素 21 | window.URL.revokeObjectURL(href); //释放掉blob对象 22 | } else { 23 | console.warn('不是blob对象类型的参数,可选择saveFileToBase64(Base64对象,文件类型)或saveFileToLink(文件链接,文件名,文件类型,进度回调方法)') 24 | } 25 | } -------------------------------------------------------------------------------- /src/saveFileToLink.js: -------------------------------------------------------------------------------- 1 | import { CheckUrl } from './utils'; 2 | import saveFileToBlob from './saveFileToBlob'; 3 | 4 | /** 5 | * 文件链接转文件流下载--主要针对pdf 解决谷歌浏览器a标签下载pdf直接打开的问题 6 | * @param url :文件链接 7 | * @param fileName :文件名; 8 | * @param type :文件类型; 9 | * @param fn :进度回调方法; 10 | */ 11 | export default function saveFileToLink(url, fileName, type, fn) { 12 | if (!CheckUrl(url)) { 13 | throw new Error("传入参数不合法,不是标准的文件链接"); 14 | } else { 15 | var xhr = new XMLHttpRequest(); 16 | url = url.includes('https:') ? url.replace('https:', '') : url.replace('http:', '');//资源路径动态获取请求的方式HTTPS或HTTP 17 | xhr.open('get', url, true); 18 | xhr.setRequestHeader('Content-Type', `application/${type}`); 19 | xhr.setRequestHeader("If-Modified-Since", "0");//解决缓存问题,每次请求都去请求服务器获取最新数据 20 | xhr.responseType = "blob"; 21 | xhr.onprogress = function (e) {//文件下载进度 22 | if (fn && typeof fn == 'function') { 23 | fn(e);//监听文件下载进度; 24 | } 25 | }, 26 | xhr.onload = function () { 27 | if (this.status == 200) { 28 | //接受二进制文件流 29 | var blob = this.response; 30 | saveFileToBlob(blob, fileName, type) 31 | } 32 | }, 33 | xhr.send(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 校验是否url链接 4 | * @param url :url链接 5 | * @returns {Bool}:是否url链接 6 | */ 7 | export function CheckUrl(url) { 8 | let reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\/])+$/; 9 | return reg.test(url); 10 | } 11 | 12 | /** 13 | * 校验是否base64Str字符串 14 | * @param base64Str :base64Str字符串 15 | * @returns {Bool}:是否base64Str字符串 16 | */ 17 | export function isBase64(base64Str) { 18 | let base64Pattern = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i; 19 | return base64Pattern.test(base64Str); 20 | } --------------------------------------------------------------------------------