vue3中下载各类文件

3,476 阅读3分钟

主推方法

先来推一手比较简短的方法,利用XMLHttpRequest实现下载功能 封装方法

export function downloadFile(obj: { name: string, url: string }) {
  var xhr = new XMLHttpRequest()
  xhr.open('get', process.env.VUE_APP_FILE_DOWNLOAD + obj.url)
  xhr.responseType = 'blob'
  // 关键部分
  xhr.onload = function (e) {
    // 如果请求执行成功
    if (this.status === 200) {
      var blob = this.response
      var a = document.createElement('a')
      a.href = window.URL.createObjectURL(blob)
      a.download = obj.name
      a.click()
      // 释放之前创建的URL对象
      window.URL.revokeObjectURL(blob)
    }
  }
  xhr.send()
}

调用方法

downloadFile({ name: string, url: string });

0.常见new Blob属性type参考地址

juejin.cn/post/704371…

1.实现一个xlsx下载功能

1.1封装一个下载xlsx的文件的axios实例

import axios from 'axios'
// import store from '@/store'
import router from '@/router'
import { getToken } from '@/utils/auth'
console.log('axios.defaults',axios.defaults)
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
const service = axios.create({
    // axios中请求配置有baseURL选项,表示请求URL公共部分
    baseURL: process.env.VUE_APP_BASE_API,
    // 超时
    timeout: 10000,
    responseType: 'blob'
  })
// var tableName = '' // 定义表格名称
// request interceptor
service.interceptors.request.use(
  config => {
    const isToken = (config.headers || {}).isToken === false
    if (getToken() && !isToken) {
        config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
      }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)
console.log('service.defaults',service.defaults)

// response interceptor
service.interceptors.response.use(
  response => {
    const blob = new Blob([response.data], {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    })
    let patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
    let contentDisposition = null
    let result = null
    let fileName = router.currentRoute.meta.title
    if (response.headers['content-disposition'] != undefined) {
      // 文件名称存在得的情况下
      contentDisposition = decodeURI(response.headers['content-disposition'])
      result = patt.exec(contentDisposition)
      fileName = result[1]
      fileName = fileName.replace(/\"/g, '')
    }
    const objectUrl = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = objectUrl
    a.download = fileName
    if ('download' in document.createElement('a')) {
      // 支持a标签download的浏览器
      // 下面这个写法兼容火狐
      a.dispatchEvent(
        new MouseEvent('click', {
          bubbles: true,
          cancelable: true,
          view: window
        })
      )
      window.URL.revokeObjectURL(blob)
    } else {
      // 其它浏览器
      navigator.msSaveBlob(blob, fileName)
    }
  }
)

export default service

1.2封装一个下载的方法,调用上面封装的下载xlsx功能

export function exportDeclareList(params){
  return downloadRequest({
    url: `/attestationWork/exportDeclareList`,
    method:'GET',
    params,
  })
}

1.3调用这个方法,实现效果

image.png

2.实现一个下载pips文件的功能

下载功能除了响应拦截跟1.1不一样其它地方都一样

1.1封装下载请求axios实例

// 响应请求拦截
service.interceptors.response.use(
  response => {
    const blob = new Blob([response.data], {
      type: 'application/octet-stream'
    })
    const patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
    let contentDisposition;
    let result;
    let fileName="某个pips文件.pips";
    if (response.headers['content-disposition'] != undefined) {
      // 文件名称存在得的情况下
      contentDisposition = decodeURI(response.headers['content-disposition'])
      result = patt.exec(contentDisposition)
      fileName = result[1]
      fileName = fileName.replace(/"/g, '')
      console.log('fileName',fileName)
    }
    const objectUrl = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = objectUrl
    a.download = fileName
    if ('download' in document.createElement('a')) {
      // 支持a标签download的浏览器
      // 下面这个写法兼容火狐
      a.dispatchEvent(
        new MouseEvent('click', {
          bubbles: true,
          cancelable: true,
          view: window
        })
      )
      // 释放这个临时的对象url
      window.URL.revokeObjectURL(objectUrl)
    } else {
      // 其它浏览器
      // navigator.msSaveBlob(blob, fileName)
    }
  }
)

2.1实现效果

image.png

3.前端根据节点生成一个pdf并下载

需要用到两个插件html2canvas,jspdf

3.1封装一个文件exportDataPdf.ts

import html2canvas from 'html2canvas';
import jsPDF from 'jspdf'

function exportDataPdf(el: HTMLElement, fileName: string) {
  html2canvas(el, {
    scale: 3, // 设置缩放
    useCORS: true, // 允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
    allowTaint: true,
    logging: false, // 打印日志用的 可以不加默认为false
    backgroundColor: '#ffffff'
  }).then((canvas) => {
    const contentWidth = canvas.width;
    const contentHeight = canvas.height;
    // 一页pdf显示html页面生成的canvas高度;
    const pageHeight = (contentWidth / 592.28) * 841.89;
    // 未生成pdf的html页面高度
    let leftHeight = contentHeight;
    // 页面偏移
    let position = 0;
    // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
    const imgWidth = 595.28;
    const imgHeight = (595.28 / contentWidth) * contentHeight;
    const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
    // 添加水印
    // ctx.textAlign = 'center';
    // ctx.textBaseline = 'middle';
    // ctx.rotate((25 * Math.PI) / 180);
    ctx.font = '20px Microsoft Yahei';
    // ctx.fillStyle = 'rgba(184, 184, 184, 0.8)';
    // for (let i = contentWidth * -1; i < contentWidth; i += 240) {
    //   for (let j = contentHeight * -1; j < contentHeight; j += 100) {
    //     // 填充文字,x 间距, y 间距
    //     ctx.fillText('水印名', i, j);
    //   }
    // }
    const pageData = canvas.toDataURL('image/jpeg', 1.0);
    const pdf = new jsPDF("p", "pt", "a4");
    if (leftHeight < pageHeight) {
      // 在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
      pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
    } else {
    // 分页
    while (leftHeight > 0) {
        pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
        leftHeight -= pageHeight;
        position -= 841.89;
        // 避免添加空白页
        if (leftHeight > 0) {
           pdf.addPage();
        }
    }
	}
	// 可动态生成
	pdf.save(`${fileName}.pdf`);
  })
}

export default exportDataPdf;

3.2调用exportDataPdf方法

<div ref="pdfDomContainer"></div>
let pdfDomContainer = ref<HTMLElement>();
exportDataPdf(pdfDomContainer.value, '某某pdfwen文件名字不带后缀');

3.3实现效果如下

image.png

4.前端根据word模板充填数据并下载充填好数据的word

4.1封装一个方法文件

import Docxtemplater from "docxtemplater"
import PizZip from "pizzip"
import JSZipUtils from "jszip-utils"
import { saveAs } from 'file-saver'
import expressions from "angular-expressions"
import { assign } from "lodash"

export default function ExportBriefDataDocx(tempDocxPath, data, fileName) {

  expressions.filters.lower = function(input) {

    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 scopeList = context.scopeList
        const num = context.num
        for (let i = 0, len = num + 1; i < len; i++) {
          obj = assign(obj, scopeList[i])
        }
        return expr(scope, obj)
      }
    }
  }
  JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
    if (error) {
      console.log(error)
    }

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

      }
      console.log({ error: e })
      // 当使用json记录时,此处抛出错误信息
      throw error
    }
    // 生成一个代表Docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
    const out = doc.getZip().generate({
      type: 'blob',
      mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    })
    // 将目标文件对象保存为目标类型的文件,并命名
    saveAs(out, fileName)
  })
}

4.2调用ExportBriefDataDocx方法

function exportDocx() {
      state.docxData.tableData = state.tableData
      const fileUrl = new URL(`../../../../assets/report.docx`, import.meta.url).href
      ExportBriefDataDocx(fileUrl, state.docxData, state.docxData.title+'.docx')
}

4.3实现下载效果

image.png

4.4原来初始的放在assets里面的下载word模板

image.png