vue3+ts 前端导出pdf

vue3.0 ts 前端利用HTML2canvas与JSpdf插件实现将页面保存为pdf格式下载

1.安装html2Canvas 与JsPDF

npm install --save html2canvas
npm install --save jspdf

 2.html代码

<el-button @click="weeklyReport('周报')">周报</a-button>
<div id="capture">
      <!-- 页面组件 -->
  	<WeeklyReport></WeeklyReport>
</div>

3.ts代码

<script lang="ts" setup>

  import { reactive, ref, createVNode, onMounted } from 'vue'
  import htmlToPdf from '@/utils/pdf'//引入封装好的ts文件
   const weeklyReport = (text:string) => {
    console.log('生成周报')
    htmlToPdf(text, '#capture')
  }
</script>

4.封装好的utils pdf

import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
// title:下载文件的名称  htmlId:包裹的标签的id
const htmlToPdf = (title: string, htmlId: string) => {
  var element = document.querySelector(htmlId) as HTMLElement
  window.pageYOffset = 0
  document.documentElement.scrollTop = 0
  document.body.scrollTop = 0
  setTimeout(() => {
    // // 以下注释的是增加导出的pdf水印 !!!!!!!!!!!!!
    // const value = '我是水印'
    // //创建一个画布
    // let can = document.createElement('canvas')
    // //设置画布的长宽
    // can.width = 400
    // can.height = 500

    // let cans = can.getContext('2d') as any
    // //旋转角度
    // cans.rotate((-15 * Math.PI) / 180)
    // cans.font = '18px Vedana'
    // //设置填充绘画的颜色、渐变或者模式
    // cans.fillStyle = 'rgba(200, 200, 200, 0.40)'
    // //设置文本内容的当前对齐方式
    // cans.textAlign = 'left'
    // //设置在绘制文本时使用的当前文本基线
    // cans.textBaseline = 'Middle'
    // //在画布上绘制填色的文本(输出的文本,开始绘制文本的X坐标位置,开始绘制文本的Y坐标位置)
    // cans.fillText(value, can.width / 8, can.height / 2)
    // let div = document.createElement('div')
    // div.style.pointerEvents = 'none'
    // div.style.top = '20px'
    // div.style.left = '-20px'
    // div.style.position = 'fixed'
    // div.style.zIndex = '100000'
    // div.style.width = element.scrollHeight + 'px'
    // div.style.height = element.scrollHeight + 'px'
    // div.style.background =
    //   'url(' + can.toDataURL('image/png') + ') left top repeat'
    // element.appendChild(div) // 到页面中

    html2Canvas(element, {
      allowTaint: true,
      useCORS: true,
      scale: 2, // 提升画面质量,但是会增加文件大小
      height: element.scrollHeight, // 需要注意,element的 高度 宽度一定要在这里定义一下,不然会存在只下载了当前你能看到的页面   避雷避雷!!!
      windowHeight: element.scrollHeight,
    }).then(function (canvas) {
      var contentWidth = canvas.width
      var contentHeight = canvas.height
      // console.log('contentWidth', contentWidth)
      // console.log('contentHeight', contentHeight)
      // 一页pdf显示html页面生成的canvas高度;
      var pageHeight = (contentWidth * 841.89) / 592.28
      // 未生成pdf的html页面高度
      var leftHeight = contentHeight

      // console.log('pageHeight', pageHeight)
      // console.log('leftHeight', leftHeight)
      // 页面偏移
      var position = 0
      // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高  //40是左右页边距
      var imgWidth = 595.28 - 40
      var imgHeight = (592.28 / contentWidth) * contentHeight

      var pageData = canvas.toDataURL('image/jpeg', 1.0)

      var pdf = new JsPDF('p', 'pt', 'a4')

      // 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
      // 当内容未超过pdf一页显示的范围,无需分页
      if (leftHeight < pageHeight) {
        // console.log('没超过1页')
        pdf.addImage(pageData, 'JPEG', 20, 20, imgWidth, imgHeight)
      } else {
        while (leftHeight > 0) {
          // console.log('超过1页')
          pdf.addImage(pageData, 'JPEG', 20, position, imgWidth, imgHeight)
          leftHeight -= pageHeight
          position -= 841.89
          // 避免添加空白页
          if (leftHeight > 0) {
            pdf.addPage()
          }
        }
      }
      pdf.save(title + '.pdf')
    })
  }, 1000)
}

export default htmlToPdf

*5.添加多重水印

import { useUserStore } from '@/store'
import { dayjs } from 'element-plus'
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
const store = useUserStore()
// title:下载文件的名称  htmlId:包裹的标签的id
const htmlToPdf = (title: string, htmlId: string) => {
	var element = document.querySelector(htmlId) as HTMLElement
	window.pageYOffset = 0
	document.documentElement.scrollTop = 0
	document.body.scrollTop = 0
	setTimeout(() => {
		const fontSize = 15; // 字体大小
		const degree = -15; // 旋转角度,顺时针为正,逆时针为负
		const areaWidth = window.innerWidth; // 水印区域的宽度
		const areaHeight = window.innerHeight; // 水印区域的高度
		const nameStr = store.userInfoList?.name;
		const timeStr = dayjs(new Date()).format('YYYY-MM-DD');
		const lineSpace = 250; // 每行文字的垂直间隔(包含文字高度),px
		const colSpace = 3; // 显示文字的区域的宽度与文字宽度的比例  (文字左右间距)
		//创建画布
		const canvas = document.createElement('canvas');
		canvas.setAttribute('width', areaWidth + '')
		canvas.setAttribute('height', areaHeight + '')
		const ctx = canvas.getContext('2d') as any;
		ctx.rotate(degree * Math.PI / 180);
		ctx.font = `${fontSize}px Microsoft Yahei`; // 设置字体及大小
		const textWidth = ctx.measureText(nameStr).width // 获取文字宽度
		const textUnitWidth = textWidth * colSpace; // 一个文字单元的宽度(文字宽度+左右空白)
		ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; // 字体的颜色
		ctx.textAlign = "center"; // 文本的对齐方式
		ctx.textBaseline = "middle"; // 文本的基线属性
		// ctx.globalAlpha = 0.5; // 透明度
		// ctx.translate(100, 100); // 给画面一个基础偏移量,也可以省略该值
		let xNum = Math.ceil(areaWidth / textUnitWidth) //不旋转时横向可以展示的最多文字单元数
		let yNum = Math.ceil(areaHeight / lineSpace)//(不旋转时)纵向可以展示的最多文字单元数
		// 当文字旋转时,有一部分文字会被转走,需要扩展写字的范围,使用正弦函数确定扩展的最大范围
		let xStart = 0, yStart = 0, sin = Math.sin(Math.abs(degree) * Math.PI / 180);
		if (degree > 0) {
			// 顺时针旋转时,右侧和上侧可能会有空余
			xNum += Math.ceil(sin * areaHeight / textUnitWidth);
			yStart = Math.ceil(sin * areaWidth / lineSpace) + -1;
		} else {
			// 逆时针旋转时,左侧和下侧可能会有空余
			xStart = Math.ceil(sin * areaHeight / textUnitWidth) * -1;
			yNum += Math.ceil(sin * areaWidth / lineSpace);
		}
		for (let x = xStart; x < xNum; x++) {
			for (let y = yStart; y < yNum; y++) {
				const offsetY = y % 2 == 0 ? 0 : textUnitWidth / 2; // 隔行横向偏移一半的距离
				const startX = textUnitWidth * x + offsetY; // 文字的X轴起始点
				const startY = lineSpace * y; // 文字的Y轴起始点
				ctx.fillText(nameStr, startX, startY);
				ctx.fillText(timeStr, startX, startY + fontSize * 1.5);
			}
		}
		
		let div = document.createElement('div')
		div.style.pointerEvents = 'none'
		div.style.top = '20px'
		div.style.left = '-20px'
		div.style.position = 'fixed'
		div.style.zIndex = '100000'
		div.style.width = element.scrollHeight + 'px'
		div.style.height = element.scrollHeight + 'px'
		div.style.background =
			'url(' + canvas.toDataURL('image/png') + ') left top repeat'
		element.appendChild(div) // 到页面中
		html2Canvas(element, {
			allowTaint: true,
			useCORS: true,
			scale: 1, // 提升画面质量,但是会增加文件大小
			height: element.scrollHeight, // 需要注意,element的 高度 宽度一定要在这里定义一下,不然会存在只下载了当前你能看到的页面   避雷避雷!!!
			windowHeight: element.scrollHeight,
		}).then(function (canvas) {
			var contentWidth = canvas.width
			var contentHeight = canvas.height
			// console.log('contentWidth', contentWidth)
			// console.log('contentHeight', contentHeight)
			// 一页pdf显示html页面生成的canvas高度;
			var pageHeight = (contentWidth * 841.89) / 592.28
			// 未生成pdf的html页面高度
			var leftHeight = contentHeight
			// console.log('pageHeight', pageHeight)
			// console.log('leftHeight', leftHeight)
			// 页面偏移
			var position = 0
			// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高  //40是左右页边距
			var imgWidth = 595.28 - 40
			var imgHeight = (592.28 / contentWidth) * contentHeight
			var pageData = canvas.toDataURL('image/jpeg', 1.0)
			var pdf = new JsPDF('p', 'pt', 'a4')
			// 有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
			// 当内容未超过pdf一页显示的范围,无需分页
			if (leftHeight < pageHeight) {
				// console.log('没超过1页')
				pdf.addImage(pageData, 'JPEG', 20, 20, imgWidth, imgHeight)
			} else {
				while (leftHeight > 0) {
					// console.log('超过1页')
					pdf.addImage(pageData, 'JPEG', 20, position, imgWidth, imgHeight)
					leftHeight -= pageHeight
					position -= 841.89
					// 避免添加空白页
					if (leftHeight > 0) {
						pdf.addPage()
					}
				}
			}
			pdf.save(title + '.pdf')
		})
	}, 1000)
}

export default htmlToPdf

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值