@yyman001
2018-07-07T15:15:04.000000Z
字数 5260
阅读 3922
web 打包
传统下载压缩包通过后端打包好文件并返回url地址进行下载,目前主流浏览器可以实现在前端下载好文件进行打包
下载图片方式有几种
- ajax 直接获取buffer
- new Image()
- <img/>
第二种和第三种其实是一样,但第二种不需要在页面上生成dom元素,但可能会存在跨域问题.
我实现的方式选用new Image() 下载图片,通过canvas元素把数据转成Blob,然后建立一个压缩包对象,把数据push进去
/*** 加载图片资源并转成blob* @param {object} object* @returns {Promise}*/function getImage (object) {let that = thisreturn new Promise((resolve, reject) => {let img = new Image()img.crossOrigin = 'Anonymous'img.onload = function () {that.createCanvas(img)that.canvas.toBlob(function (blob) {if (object.blob === null) {object.blob = blobthat.loaded.push(object)}img.onload = nullimg = nullresolve(object)}, "image/png")}img.onerror = function (err) {img.onerror = nullimg = nullobject.blob = nullreject(object)}img.src = object.urlif (img.complete || img.complete === undefined) {img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";img.src = object.url}})}
let zip = new JSZip()
为什么这里不用const?因为我们还需要清空,重置,初始化这个对象.
2.新建一个文件夹对象(可以省略)
// folderName - 文件夹名称let folder = zip.folder( folderName )
3.添加文件到文件夹中
// fileName - 文件名.后缀名 eg: test.png// fileType - 文件名数据类 eg: file.blobfolder.file( fileName , fileType )// 如果不使用文件夹zip.file( fileName , fileType )
4.压缩并打包下载文件
// content 打包的文件内容数据// zipName 压缩包名称 eg: test.zipzip.generateAsync({type: "blob"}).then((content) => {FileSaver.saveAs(content, zipName)// 清空文件夹对象folder = null})
上面方法我是封装到一个对象里面的,这样就更加方便了
完整代码
如何使用?
// 1. 引入文件import { DownClass } from '@/utils/DownClass'// 2. 实例化对象const DownClass = new DownClass()// 3. 传入需要下载的图片对象(指定了格式)let testObject = {lock: false,fullName: 'test.png'blob: <Blob>,url:'http://test.com/test/test.png'}// 4.打包下载// - 单个文件下载 (下载对象格式)DownClass.downFile(testObject)// 把上面的对象通过数组方式传入let fileArray = [testObject...]// 传入需要下载图片列表数组DownClass.queue = fileArray// 触发下载打包(是一个异步进程)// 通过 `toZipLock` 属性是否已经打包完成DownClass..toZip(zipName)
DownClass.js
/* eslint-disable *//*** DownClass.js* 前端打包图片文件* @a:wangdongman*/const FileSaver = require('file-saver')const JSZip = require('jszip')export class DownClass {constructor (queue, maxThread) {/** 加载队列* */this.queue = Array.isArray(queue) ? queue : []/** 已经加载完队列* */this.loaded = []/** 失败队列* */this.fail = []/** 最大线程 ( 功能暂时未实现 )* */this.maxThread = maxThread || 3/** 画布对象* */this.canvas = nullthis.ctx = null/** 单个文件下载锁定状态* */this.lock = false/** 压缩包锁定状态* */this.toZipLock = false/** 压缩包对象* */this.zip = new JSZip()}/***获取图片数据* @param img* @returns {{base64: string, Blob: *}}*/getImageData (img) {let that = thisif (this.canvas === null) {this.canvas = document.createElement("canvas")}this.canvas.width = img.width;this.canvas.height = img.height;if (this.ctx === null) {this.ctx = this.canvas.getContext("2d")}this.ctx.drawImage(img, 0, 0, img.width, img.height)return {base64: that.canvas.toDataURL("image/png"),Blob: that.dataURItoBlob(that.canvas.toDataURL("image/png"))}}/*** 创建画布对象* @param { images } img - 图片对象*/createCanvas (img) {if (this.canvas === null) {this.canvas = document.createElement("canvas")}this.canvas.width = img.width;this.canvas.height = img.height;if (this.ctx === null) {this.ctx = this.canvas.getContext("2d")}this.ctx.drawImage(img, 0, 0, img.width, img.height)}/*** 加载图片资源并转成blob* @param {object} object* @returns {Promise}*/getImage (object) {let that = thisreturn new Promise((resolve, reject) => {let img = new Image()img.crossOrigin = 'Anonymous'img.onload = function () {that.createCanvas(img)that.canvas.toBlob(function (blob) {if (object.blob === null) {object.blob = blobthat.loaded.push(object)}img.onload = nullimg = nullresolve(object)}, "image/png")}img.onerror = function (err) {img.onerror = nullimg = nullobject.blob = nullreject(object)}img.src = object.urlif (img.complete || img.complete === undefined) {img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";img.src = object.url}})}/*** 加载队列资源* @returns {Promise.<void>}*/async loadImages () {if (this.lock) {console.warn('locking')return}this.lock = truefor (let i = 0, len = this.queue.length; i < len; i++) {if (this.queue[i].blob !== null) {continue}try {let result = await this.getImage(this.queue[i])console.log('加载文件:loadImages:', result)} catch (err) {console.error(err)}}this.lock = false}/*** 静态方法: 保存文件* @param {String} name - 文件名* @param {Blob} blob - 数据*/static downImagesFile (name, blob) {FileSaver.saveAs(blob, `${name}.png`)}/*** 单独下载一个文件* @param {Object} object - 下载对象* @returns {Promise.<void>}*/async downFile (object) {if (Object.prototype.toString.call(object) !== '[object Object]') {console.warn('请传入一个对象!')return}if (object.lock) {console.log('正在下载')return}object.lock = trueawait this.getImage(object)object.lock = falseconsole.log('object:', object)DownClass.downImagesFile(object.fullName, object.blob)}/*** 打包资源* @param {String} [fileName] - 打包文件名* @returns {Promise.<void>}*/async toZip (fileName) {console.log('this.toZipLock:', this.toZipLock)if (this.toZipLock) {console.warn('正在带包zip')return}this.toZipLock = truelet time = new Date().getTime()let zipName = fileName + time + '.zip'console.log('1.加载文件')await this.loadImages()console.log('2.打包', this.loaded)let folder = this.zip.folder(fileName + time)this.loaded.forEach((file) => {console.log('file:', file);// this.zip.file(`${file.fullName}.png`, file.blob)folder.file(`${file.fullName}.png`, file.blob);})this.zip.generateAsync({type: "blob"}).then((content) => {FileSaver.saveAs(content, zipName)this.toZipLock = falsefolder = null})}clearImages () {this.queue = []this.loaded = []this.fail = []this.zip = new JSZip()}/*** 销毁*/destroy () {this.queue = []this.loaded = []this.fail = []this.canvas = nullthis.ctx = nullthis.zip = null}}