[关闭]
@yyman001 2018-07-07T15:15:04.000000Z 字数 5260 阅读 3661

web前端打包下载图片文件

web 打包


传统下载压缩包通过后端打包好文件并返回url地址进行下载,目前主流浏览器可以实现在前端下载好文件进行打包

优点

缺点

需要使用的js文件

实现原理

下载图片方式有几种
- ajax 直接获取buffer
- new Image()
- <img/>

第二种和第三种其实是一样,但第二种不需要在页面上生成dom元素,但可能会存在跨域问题.
我实现的方式选用new Image() 下载图片,通过canvas元素把数据转成Blob,然后建立一个压缩包对象,把数据push进去

  1. 获取下载文件
  1. /**
  2. * 加载图片资源并转成blob
  3. * @param {object} object
  4. * @returns {Promise}
  5. */
  6. function getImage (object) {
  7. let that = this
  8. return new Promise((resolve, reject) => {
  9. let img = new Image()
  10. img.crossOrigin = 'Anonymous'
  11. img.onload = function () {
  12. that.createCanvas(img)
  13. that.canvas.toBlob(function (blob) {
  14. if (object.blob === null) {
  15. object.blob = blob
  16. that.loaded.push(object)
  17. }
  18. img.onload = null
  19. img = null
  20. resolve(object)
  21. }, "image/png")
  22. }
  23. img.onerror = function (err) {
  24. img.onerror = null
  25. img = null
  26. object.blob = null
  27. reject(object)
  28. }
  29. img.src = object.url
  30. if (img.complete || img.complete === undefined) {
  31. img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
  32. img.src = object.url
  33. }
  34. })
  35. }
  1. 打包文件,先实例化一个对象
  1. let zip = new JSZip()

为什么这里不用const?因为我们还需要清空,重置,初始化这个对象.
2.新建一个文件夹对象(可以省略)

  1. // folderName - 文件夹名称
  2. let folder = zip.folder( folderName )

3.添加文件到文件夹中

  1. // fileName - 文件名.后缀名 eg: test.png
  2. // fileType - 文件名数据类 eg: file.blob
  3. folder.file( fileName , fileType )
  4. // 如果不使用文件夹
  5. zip.file( fileName , fileType )

4.压缩并打包下载文件

  1. // content 打包的文件内容数据
  2. // zipName 压缩包名称 eg: test.zip
  3. zip.generateAsync({type: "blob"}).then((content) => {
  4. FileSaver.saveAs(content, zipName)
  5. // 清空文件夹对象
  6. folder = null
  7. })

上面方法我是封装到一个对象里面的,这样就更加方便了
完整代码
如何使用?

  1. // 1. 引入文件
  2. import { DownClass } from '@/utils/DownClass'
  3. // 2. 实例化对象
  4. const DownClass = new DownClass()
  5. // 3. 传入需要下载的图片对象(指定了格式)
  6. let testObject = {
  7. lock: false,
  8. fullName: 'test.png'
  9. blob: <Blob>,
  10. url:'http://test.com/test/test.png'
  11. }
  12. // 4.打包下载
  13. // - 单个文件下载 (下载对象格式)
  14. DownClass.downFile(testObject)
  15. // 把上面的对象通过数组方式传入
  16. let fileArray = [testObject...]
  17. // 传入需要下载图片列表数组
  18. DownClass.queue = fileArray
  19. // 触发下载打包(是一个异步进程)
  20. // 通过 `toZipLock` 属性是否已经打包完成
  21. DownClass..toZip(zipName)

DownClass.js

  1. /* eslint-disable */
  2. /**
  3. * DownClass.js
  4. * 前端打包图片文件
  5. * @a:wangdongman
  6. */
  7. const FileSaver = require('file-saver')
  8. const JSZip = require('jszip')
  9. export class DownClass {
  10. constructor (queue, maxThread) {
  11. /*
  12. * 加载队列
  13. * */
  14. this.queue = Array.isArray(queue) ? queue : []
  15. /*
  16. * 已经加载完队列
  17. * */
  18. this.loaded = []
  19. /*
  20. * 失败队列
  21. * */
  22. this.fail = []
  23. /*
  24. * 最大线程 ( 功能暂时未实现 )
  25. * */
  26. this.maxThread = maxThread || 3
  27. /*
  28. * 画布对象
  29. * */
  30. this.canvas = null
  31. this.ctx = null
  32. /*
  33. * 单个文件下载锁定状态
  34. * */
  35. this.lock = false
  36. /*
  37. * 压缩包锁定状态
  38. * */
  39. this.toZipLock = false
  40. /*
  41. * 压缩包对象
  42. * */
  43. this.zip = new JSZip()
  44. }
  45. /**
  46. *获取图片数据
  47. * @param img
  48. * @returns {{base64: string, Blob: *}}
  49. */
  50. getImageData (img) {
  51. let that = this
  52. if (this.canvas === null) {
  53. this.canvas = document.createElement("canvas")
  54. }
  55. this.canvas.width = img.width;
  56. this.canvas.height = img.height;
  57. if (this.ctx === null) {
  58. this.ctx = this.canvas.getContext("2d")
  59. }
  60. this.ctx.drawImage(img, 0, 0, img.width, img.height)
  61. return {
  62. base64: that.canvas.toDataURL("image/png"),
  63. Blob: that.dataURItoBlob(that.canvas.toDataURL("image/png"))
  64. }
  65. }
  66. /**
  67. * 创建画布对象
  68. * @param { images } img - 图片对象
  69. */
  70. createCanvas (img) {
  71. if (this.canvas === null) {
  72. this.canvas = document.createElement("canvas")
  73. }
  74. this.canvas.width = img.width;
  75. this.canvas.height = img.height;
  76. if (this.ctx === null) {
  77. this.ctx = this.canvas.getContext("2d")
  78. }
  79. this.ctx.drawImage(img, 0, 0, img.width, img.height)
  80. }
  81. /**
  82. * 加载图片资源并转成blob
  83. * @param {object} object
  84. * @returns {Promise}
  85. */
  86. getImage (object) {
  87. let that = this
  88. return new Promise((resolve, reject) => {
  89. let img = new Image()
  90. img.crossOrigin = 'Anonymous'
  91. img.onload = function () {
  92. that.createCanvas(img)
  93. that.canvas.toBlob(function (blob) {
  94. if (object.blob === null) {
  95. object.blob = blob
  96. that.loaded.push(object)
  97. }
  98. img.onload = null
  99. img = null
  100. resolve(object)
  101. }, "image/png")
  102. }
  103. img.onerror = function (err) {
  104. img.onerror = null
  105. img = null
  106. object.blob = null
  107. reject(object)
  108. }
  109. img.src = object.url
  110. if (img.complete || img.complete === undefined) {
  111. img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
  112. img.src = object.url
  113. }
  114. })
  115. }
  116. /**
  117. * 加载队列资源
  118. * @returns {Promise.<void>}
  119. */
  120. async loadImages () {
  121. if (this.lock) {
  122. console.warn('locking')
  123. return
  124. }
  125. this.lock = true
  126. for (let i = 0, len = this.queue.length; i < len; i++) {
  127. if (this.queue[i].blob !== null) {
  128. continue
  129. }
  130. try {
  131. let result = await this.getImage(this.queue[i])
  132. console.log('加载文件:loadImages:', result)
  133. } catch (err) {
  134. console.error(err)
  135. }
  136. }
  137. this.lock = false
  138. }
  139. /**
  140. * 静态方法: 保存文件
  141. * @param {String} name - 文件名
  142. * @param {Blob} blob - 数据
  143. */
  144. static downImagesFile (name, blob) {
  145. FileSaver.saveAs(blob, `${name}.png`)
  146. }
  147. /**
  148. * 单独下载一个文件
  149. * @param {Object} object - 下载对象
  150. * @returns {Promise.<void>}
  151. */
  152. async downFile (object) {
  153. if (Object.prototype.toString.call(object) !== '[object Object]') {
  154. console.warn('请传入一个对象!')
  155. return
  156. }
  157. if (object.lock) {
  158. console.log('正在下载')
  159. return
  160. }
  161. object.lock = true
  162. await this.getImage(object)
  163. object.lock = false
  164. console.log('object:', object)
  165. DownClass.downImagesFile(object.fullName, object.blob)
  166. }
  167. /**
  168. * 打包资源
  169. * @param {String} [fileName] - 打包文件名
  170. * @returns {Promise.<void>}
  171. */
  172. async toZip (fileName) {
  173. console.log('this.toZipLock:', this.toZipLock)
  174. if (this.toZipLock) {
  175. console.warn('正在带包zip')
  176. return
  177. }
  178. this.toZipLock = true
  179. let time = new Date().getTime()
  180. let zipName = fileName + time + '.zip'
  181. console.log('1.加载文件')
  182. await this.loadImages()
  183. console.log('2.打包', this.loaded)
  184. let folder = this.zip.folder(fileName + time)
  185. this.loaded.forEach((file) => {
  186. console.log('file:', file);
  187. // this.zip.file(`${file.fullName}.png`, file.blob)
  188. folder.file(`${file.fullName}.png`, file.blob);
  189. })
  190. this.zip.generateAsync({type: "blob"}).then((content) => {
  191. FileSaver.saveAs(content, zipName)
  192. this.toZipLock = false
  193. folder = null
  194. })
  195. }
  196. clearImages () {
  197. this.queue = []
  198. this.loaded = []
  199. this.fail = []
  200. this.zip = new JSZip()
  201. }
  202. /**
  203. * 销毁
  204. */
  205. destroy () {
  206. this.queue = []
  207. this.loaded = []
  208. this.fail = []
  209. this.canvas = null
  210. this.ctx = null
  211. this.zip = null
  212. }
  213. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注