vue项目导出图片至word方法。

实现以下两点功能:
1.导出单条数据至word中,图片还需支持多张。

2.导出多条数据至zip压缩包中,并且有图片也需要导出至word中,支持多张。

废话不多说开整!

首先在mixins文件中创建一个 exportWordImage.js 代码如下:
import Docxtemplater from 'docxtemplater'
import PizZip from 'pizzip'
import JSZipUtils from 'jszip-utils'
import { saveAs } from 'file-saver'
import JSZip from 'jszip'
export default {
  data () {
    return {
      zipName: '导出word.zip',
      zip: null,
      download: [],
      length: 0
    }
  },
  watch: {
    download (val) {
      if (val.length === this.length) {
        var word = this.zip.generate({ type: 'blob' })
        saveAs(word, this.zipName)
        this.zip = null
        this.download = []
      }
    }
  },
  methods: {
    /**
     * 将base64格式的数据转为ArrayBuffer
     * @param {Object} dataURL base64格式的数据
     */
    base64DataURLToArrayBuffer (dataURL) {
      const base64Regex = /^data:image\/(png|jpg|jpeg|svg|svg\+xml);base64,/
      // const base64Regex = /^data:image\/(png|jpg|svg|svg\+xml);base64,/
      if (!base64Regex.test(dataURL)) {
        return false
      }
      const stringBase64 = dataURL.replace(base64Regex, '')
      let binaryString
      if (typeof window !== 'undefined') {
        binaryString = window.atob(stringBase64)
      } else {
        binaryString = Buffer.from(stringBase64, 'base64').toString('binary')
      }
      const len = binaryString.length
      const bytes = new Uint8Array(len)
      for (let i = 0; i < len; i++) {
        const ascii = binaryString.charCodeAt(i)
        bytes[i] = ascii
      }
      return bytes.buffer
    },
    create (res = '') {
      if (res) {
        this.zip = new JSZip(res)
      } else {
        this.zip = new JSZip()
      }
    },
    // 导出多条数据执行这个方法
    ExportWordLists (url, list) {
      this.length = list.length
      list.forEach((item) => {
        var obj = item
        this.ExportBriefDataDocxs(url, obj, item.imgData)
      })
    },
    ExportBriefDataDocxs (tempDocxPath, data, fileName, imgSize) {
      console.log('ExportBriefDataDocxs', tempDocxPath, data, fileName, imgSize)
      var _this = this
      // 这里要引入处理图片的插件
      var ImageModule = require('docxtemplater-image-module-free')
      var expressions = require('angular-expressions')
      var assign = require('lodash/assign')
      var last = require('lodash/last')
      expressions.filters.lower = function (input) {
        // This condition should be used to make sure that if your input is
        // undefined, your output will be undefined as well and will not
        // throw an error
        if (!input) return input
        // toLowerCase() 方法用于把字符串转换为小写。
        return input.toLowerCase()
      }
      function angularParser (tag) {
        tag = tag
          .replace(/^\.$/, 'this')
          .replace(/(’|‘)/g, '')
          .replace(/(“|”)/g, '')
        const expr = expressions.compile(tag)
        return {
          get: function (scope, context) {
            let obj = {}
            const index = last(context.scopePathItem)
            const scopeList = context.scopeList
            const num = context.num
            for (let i = 0, len = num + 1; i < len; i++) {
              obj = assign(obj, scopeList[i])
            }
            // word模板中使用 $index+1 创建递增序号
            obj = assign(obj, { $index: index })
            return expr(scope, obj)
          }
        }
      }
      JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
        if (error) {
          console.log(error)
        }
        expressions.filters.size = function (input, width, height) {
          return {
            data: input,
            size: [width, height]
          }
        }
        let opts = {}
        opts = {
          // 图像是否居中
          centered: true
        }
        opts.fileType = 'docx'
        opts.getImage = (chartId) => {
          // 将base64的数据转为ArrayBuffer
          return _this.base64DataURLToArrayBuffer(chartId)
        }
        opts.getSize = function (img, tagValue, tagName) {
          // 自定义指定图像大小
          if (tagName === 'signature') {
            return [80, 40]
          } else {
            return [350, 250]
          }
        }

        // 创建一个JSZip实例,内容为模板的内容
        const zip = new JSZip(content)
        // 创建并加载 Docxtemplater 实例对象
        // 设置模板变量的值
        let doc = new Docxtemplater() // eslint-disable-line
        doc.attachModule(new ImageModule(opts))
        doc.loadZip(zip)
        doc.setOptions({ parser: angularParser })
        doc.setData({ ...data })
        try {
          // 呈现文档,会将内部所有变量替换成值,
          doc.render()
        } catch (error) {
          const e = {
            message: error.message,
            name: error.name,
            stack: error.stack,
            properties: error.properties

          }
          console.log('err', { error: e })
          // 当使用json记录时,此处抛出错误信息
          throw error
        }
        // 生成一个代表Docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
        const out = doc.getZip().generate({ type: 'ArrayBuffer' })
        this.zip.file(data.docName || data.title + '.docx', out, { binary: true })
        this.download.push(data.proposalId)
      })
    },
    // 导出单条数据执行这个方法
    ExportBriefDataDocx (tempDocxPath, data, fileName, imgSize) {
      console.log('ExportBriefDataDocx', tempDocxPath, data, fileName, imgSize)
      var _this = this
      // 这里要引入处理图片的插件
      var ImageModule = require('docxtemplater-image-module-free')
      var expressions = require('angular-expressions')
      var assign = require('lodash/assign')
      var last = require('lodash/last')
      expressions.filters.lower = function (input) {
        // This condition should be used to make sure that if your input is
        // undefined, your output will be undefined as well and will not
        // throw an error
        if (!input) return input
        // toLowerCase() 方法用于把字符串转换为小写。
        return input.toLowerCase()
      }
      function angularParser (tag) {
        tag = tag
          .replace(/^\.$/, 'this')
          .replace(/(’|‘)/g, '')
          .replace(/(“|”)/g, '')
        const expr = expressions.compile(tag)
        return {
          get: function (scope, context) {
            let obj = {}
            const index = last(context.scopePathItem)
            const scopeList = context.scopeList
            const num = context.num
            for (let i = 0, len = num + 1; i < len; i++) {
              obj = assign(obj, scopeList[i])
            }
            // word模板中使用 $index+1 创建递增序号
            obj = assign(obj, { $index: index })
            return expr(scope, obj)
          }
        }
      }
      JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
        if (error) {
          console.log(error)
        }
        expressions.filters.size = function (input, width, height) {
          return {
            data: input,
            size: [width, height]
          }
        }
        let opts = {}
        opts = {
          // 图像是否居中
          centered: true
        }
        opts.getImage = (chartId) => {
          // 将base64的数据转为ArrayBuffer
          return _this.base64DataURLToArrayBuffer(chartId)
        }
        opts.getSize = function (img, tagValue, tagName) {
          // 自定义指定图像大小
          if (tagName === 'signature') {
            return [80, 40]
          } else {
            return [350, 250]
          }
        }

        // 创建一个JSZip实例,内容为模板的内容
        const zip = new PizZip(content)
        // 创建并加载 Docxtemplater 实例对象
        // 设置模板变量的值
        let doc = new Docxtemplater() // eslint-disable-line
        doc.attachModule(new ImageModule(opts))
        doc.loadZip(zip)
        doc.setOptions({ parser: angularParser })
        doc.setData(data)
        try {
          // 呈现文档,会将内部所有变量替换成值,
          doc.render()
        } catch (error) {
          const e = {
            message: error.message,
            name: error.name,
            stack: error.stack,
            properties: error.properties

          }
          console.log('err', { error: e })
          // 当使用json记录时,此处抛出错误信息
          throw error
        }
        // 生成一个代表Docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
        const out = doc.getZip().generate({
          type: 'blob',
          mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
        })
        // 将目标文件对象保存为目标类型的文件,并命名
        saveAs(out, data.title || fileName)
      })
    },
    /**
     * 将图片的url路径转为base64路径
     * 可以用await等待Promise的异步返回
     * @param {Object} imgUrl 图片路径
     */
    getBase64Sync (imgUrl) {
      return new Promise(function (resolve, reject) {
        // 一定要设置为let,不然图片不显示
        let image = new Image() // eslint-disable-line
        // 图片地址
        image.src = imgUrl
        // 解决跨域问题
        image.setAttribute('crossOrigin', '*') // 支持跨域图片
        // image.onload为异步加载
        image.onload = function () {
          let canvas = document.createElement('canvas') // eslint-disable-line
          canvas.width = image.width
          canvas.height = image.height
          let context = canvas.getContext('2d') // eslint-disable-line
          context.drawImage(image, 0, 0, image.width, image.height)
          // 图片后缀名
          let ext = image.src.substring(image.src.lastIndexOf('.') + 1).toLowerCase() // eslint-disable-line
          // 图片质量
          let quality = 0.8 // eslint-disable-line
          // 转成base64
          let dataurl = canvas.toDataURL('image/' + ext, quality) // eslint-disable-line
          // 返回
          resolve(dataurl)
        }
      })
    }
  }
}
在vue文件中:
<el-button type="primary"
                   @click="exportClick">导出</el-button>

import exportWordImage from '@/mixins/exportWordImage'

exportClick() {
      if (this.choose.length) {
        this.$confirm('此操作将当前选中的数据导出word, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.create()
          this.wordExport(this.choose.join(','))
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '已取消导出'
          })
        })
      } else {
        this.$message({
          message: '请至少选择一条数据',
          type: 'warning'
        })
      }
 },
 async wordExport (id) {
      const res = await this.$api.representativeMessage.representativemessageExportWord({ ids: id })
      var { data } = res
      console.log('data===>', data)
      var idArray = id.split(',')
      var numberOfIds = idArray.length
      if (numberOfIds === 1) {
        var wordArr = []
        var item = {}
        for (let i = 0; i < data.length; i++) { // eslint-disable-line
          console.log('data===>', data[i])
          item.title = data[i].title
          item.imgData = data[i].imageVo
          for (let i in item.imgData) { // eslint-disable-line
            item.imgData[i].imgUrl = await this.getBase64Sync(item.imgData[i].fullUrl)
          }
          item.userName = data[i].userName ? data[i].userName : ''
          item.userIdentity = data[i].userIdentity ? data[i].userIdentity : ''
          item.mobile = data[i].mobile ? data[i].mobile : ''
          item.address = data[i].address ? data[i].address : ''
          item.messageMessage = data[i].messageMessage ? data[i].messageMessage : ''
          item.schedule = data[i].schedule ? data[i].schedule : ''
          item.resultFeedback = data[i].resultFeedback ? data[i].resultFeedback : ''
          item.representativeResult = data[i].representativeResult ? data[i].representativeResult : ''
          item.feedbackImage = data[i].feedbackImage
          for (let i in item.feedbackImage) { // eslint-disable-line
            item.feedbackImage[i].imgUrl = await this.getBase64Sync(item.feedbackImage[i].fullUrl)
          }
        }
        wordArr.push({ ...item })
        var contentObj = wordArr[0]
        this.ExportBriefDataDocx('word/representativeMessage.docx', contentObj, '留言导出')
      } else {
        var wordArrs = []
        data.map(eItem => {
          var _item = {}
          _item.title = eItem.title
          _item.userName = eItem.userName
          _item.userIdentity = eItem.userIdentity
          _item.mobile = eItem.mobile
          _item.address = eItem.address
          _item.messageMessage = eItem.messageMessage
          _item.schedule = eItem.schedule
          _item.resultFeedback = eItem.resultFeedback
          _item.representativeResult = eItem.representativeResult
          _item.imgData = eItem.imageVo
          _item.feedbackImage = eItem.feedbackImage
          setTimeout(async () => {
            for (let i in _item.imgData) { // eslint-disable-line
              _item.imgData[i].imgUrl = await this.getBase64Sync(_item.imgData[i].fullUrl)
            }
            setTimeout(async () => {
              for (let i in _item.feedbackImage) { // eslint-disable-line
                _item.feedbackImage[i].imgUrl = await this.getBase64Sync(_item.feedbackImage[i].fullUrl)
              }
            }, 200)
            wordArrs.push(_item)
          }, 400)
        })
        setTimeout(() => {
          console.log('wordArrs===>', wordArrs)
          this.ExportWordLists('word/representativeMessage.docx', wordArrs)
        }, 2000)
      }
      this.choose = []
      this.selectObj = []
      this.list()
    }
this.create()这个方法是执行的mixins/exportWordImage.js中初始化zip的。
this.wordExport()这个方法中是处理数据的。
要保证图片的地址要转换为base64的。
数据格式如下图:
 this.ExportWordLists('word/representativeMessage.docx', wordArrs)模板的地址根据自己的实际情况来。
模板命令如下图:

if (numberOfIds === 1)我判断了如果导出是多条就走多条的逻辑,单条就走单条逻辑。
在js中方法也注明了,单条执行ExportBriefDataDocx,多条执行ExportWordLists初始化一下,在执行ExportBriefDataDocxs 。 

对你有帮助请点个赞。感谢!!
  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值