图片的展示与批量下载

        原有项目使用Vue框架和Element组件库,图片展示和下载功能可细分为:

1. 图片展示是将单个图片点击后,弹窗显示,用户选择保存则以服务端id命名保存至本地;

2.下载功能分为单个图片下载和批量下载

        原有管理系统中增加上述功能,需要新增JSZip和FileSaver两个JS库,开发步骤如下:

1. 准备工作

        安装JSZip和FileSaver

npm install jszip --save
npm install file-saver --save

        JSZip  库用于处理和生成 ZIP 文件。主要用到该库中两个方法:

  • file ()是 JSZip 对象的一个方法,用于向 ZIP 文件中添加文件。它接受两个参数:要添加到 ZIP 文件中的文件名和文件内容;
  • generateAsync()用于异步生成 ZIP 文件。它返回一个 Promise,该 Promise 在 ZIP 文件生成完成后被解析。方法使用示例;
const zip = new JSZip();

// 添加一个文件到 ZIP 中
zip.file("hello.txt", "Hello world!");

// 生成ZIP压缩文件的异步操作
zip.generateAsync({ type: "blob" })
  .then((content) => {
    // Do something 
  });

        FileSaver 则用于将数据保存为文件。主要使用saveAs()方法,接受两个参数:要保存的文件名和要保存的数据。使用方法如下:[data]为二进制数据,将被保存到新创建image.jpg的本地文件中

const blob = new Blob( [data], {type : 'image/jpeg'} );
FileSaver.saveAs( blob, 'image.jpg' );

2. 编码阶段

        在页面中引入上述库

import JSZip from 'jszip'
import FileSaver from 'file-saver'

2.1 实现单个图片的下载、展示和保存

        图片的展示和保存都需要提前获取图片,先完成单个图片请求。此处,需使用responseType: 'blob' ,因为图片是二进制数据,而不是文本数据。如果我们将responseType设置为'text',则浏览器会尝试将二进制数据解析为文本数据,这将导致数据损坏。通过将responseType设置为'blob',我们告诉浏览器将响应数据作为二进制对象处理,这样我们就可以正确地下载图片。

        图片的签名信息获取,需要通过另外的接口get到,后续处理。此外,请求涉及到了跨域问题,通过Nginx代理解决,属于后端内容不再赘述。

    // 单个图片下载
    getFile(item) {
      return new Promise((resolve, reject) => {
        this.axios({
          url: baseUrl + item.requestUrl,
          method: 'get',
          headers: {
            'Authorization': item.authToken,
            'Signature': item.reqSignature,
            'ClientId': item.clientId
          },
          // 设置此选项,响应数据类型设置为blob(arraybuffer也OK);未设置时请求数据为乱码
          responseType: 'blob'
        }).then((response) => {
          resolve(response) // 将下载的文件返回
        }).catch((error) => {
          reject(error.toString())
        })
      })
    },

        请求方法完成后,点击页面按钮触发showImage展示图片,此方法中调用getFile()获取图片,并显示在el-dialog弹窗中。实现中需要注意getFile()方法响应的数据是Blob对象,需要将其转换为url,以便赋值给el-image的src属性

    showImage(item) {
      this.startLoading()
      getImageTokenById({ idFaultResource: parseInt(item.value) }).then((resp) => {
        console.log(JSON.stringify(resp))
        if (resp.code === '200') {
          const param = {
            // resourceKey: resp.result.resourceKey,
            requestUrl: resp.result.requestUrl,
            authToken: resp.result.authToken,
            reqSignature: resp.result.reqSignature,
            clientId: resp.result.clientId
          }
          this.getFile(param).then((response) => {
            this.endLoading()
            this.dialogVisible = true
            console.log(JSON.stringify(response))
            // urlCreator用于创建URL对象。在浏览器中,window.URL和window.webkitURL对象可能存在一个或两个
            const urlCreator = window.URL || window.webkitURL
            // createObjectURL方法将一个Blob或MediaStream对象转换为URL,以便赋值给el-image的src属性
            const imageUrl = urlCreator.createObjectURL(response.data)
            console.log('URL::::' + JSON.stringify(imageUrl))
            this.dialogImageUrl = imageUrl
            this.dialogImageName = resp.result.resourceKey
            this.imageBlob = [response.data]
          }).catch((error) => {
            this.$message({
              showClose: true,
              message: '获取图片失败,' + error,
              type: 'error'
            })
            this.endLoading()
          })
        }
      }).catch((error) => {
        this.$message({
          showClose: true,
          message: error,
          type: 'error'
        })
        this.endLoading()
      })
    },

注:getImageById()方法需要提前获取签名信息;

        图片展示弹窗十分简单,添加标题,图片关闭按钮和下载按钮即可

    
      
      
      
        下载图片
      
    

        点击下载图片调用saveAs()方法保存图片,将图片文件按照imageName命名保存,并隐藏弹窗。

    saveImage(data, imageName) {
      const blob = new Blob(data, { type: 'image/jpeg' })
      FileSaver.saveAs(blob, imageName + '.jpg')
      this.dialogImageUrl = ''
      this.dialogVisible = false
      this.$message({
        showClose: true,
        message: '图片下载完成!',
        type: 'success'
      })
    },

2.2 图片批量下载并压缩

        批量下载只需要,将图片列表遍历逐个下载,待所有图片下载完成调用saveAs()方法保存并压缩生成文件夹。

    // 批量导出图片
    downloadFile() {
      const zip = new JSZip()
      const imagesPromises = []
      const cache = {}
      this.startLoading()
      getImagesTokenById ({ idTrustOrder: this.idTrustOrder }).then((resp) => {
        if (resp.code === '200') {
          const imageList = resp.result.downloadImageList
          if (imageList.length === 0) {
            this.$message({
              showClose: true,
              message: '当前无可下载的故障内容!',
              type: 'warning'
            })
            this.endLoading()
            return
          }
          imageList.map((item) => {
            const promise = this.getFile(item).then((resp) => {
              // 逐个下载图片
              console.log('获取的图片内容::' + item.resourceKey + '.jpg' + resp.data)
              // 创建文件用file()方法,文件夹用floder()方法
              zip.file(item.resourceKey + '.jpg', resp.data, { binary: true })
              cache[item.resourceKey] = resp.data
            })
            imagesPromises.push(promise)
          })
          // 生成zip文件
          Promise.all(imagesPromises)
            .then(() => {
              this.endLoading()
              zip.generateAsync({
                type: 'blob' // 文件格式
              }).then((content) => {
                // 生成二进制流
                FileSaver.saveAs(content, '图片.zip') // 利用file-saver保存文件,自定义文件名图片.zip
                this.$message({
                  showClose: true,
                  message: '文件下载完成!',
                  type: 'success'
                })
              })
            })
            .catch((error) => {
              this.$message({
                showClose: true,
                message: '文件下载失败!' + error,
                type: 'error'
              })
              this.endLoading()
            })
        }
      }).catch((error) => {
        this.$message({
          showClose: true,
          message: error,
          type: 'error'
        })
        this.endLoading()
      })
    },

3. 测试于总结

        测试功能可用,开发中遇到的问题主要是跨域,二进制数据的处理,还有IT限制我的接口

参考文献:

1. JS实现根据URL批量下载文件并压缩成zip文件_javascript技巧_脚本之家

你可能感兴趣的:(前端实践,前端,elementui,网络安全)