前端js生成自定义内容的PDF及word文件的实现

1.生成pdf:

1.使用的插件:jspdfjspdf-autotablehtml2canvas
2.插件介绍:

2.1 jspdf:前端生成和导出pdf的插件;
2.2 jspdf-autotable:可以更方便的在jspdf中生成表格,可以直接传入表格数据也可以直接传入表格dom标签;jspdf本身也有生成表格的API,只是没有jspdf-autotable方便,可以根据需要选择;
2.3 html2canvas:可以截取网页中的dom元素为canvas对象,来构建屏幕截图,如果不需要此功能,可以不使用这个插件

3.jspdf API地址jspdf-autotable样式配置参考这两个地址可以找到jspdf的大部分使用方法和配置介绍
4.demo

使用这个demo前需要注意:
1.需要自己生成simhei-normal.js/ts文件,生成方法查看上一篇文章
如果导出内容不包含中文可以不需要这个导入,相应的注释掉下面的 doc.setFont(‘simhei’) 以及 font: ‘simhei’,
2.html2canvas中获取了相应的dom元素,需要改成自己的标签元素。


import { jsPDF } from 'jspdf'
import 'jspdf-autotable'
import './simhei-normal' //jspdf自定义字体,生成步骤参见上一篇博文
const html2canvas = window['html2canvas']

export function exportPDF(filename: string) {
    const doc = new jsPDF() as any;
    doc.setFont('simhei');//simhei是自定义字体名
    //获取文件单页的宽高,单位mm
    var pageWidth = Math.floor(doc.internal.pageSize.width || doc.internal.pageSize.getWidth());
    var pageHeight = Math.floor(doc.internal.pageSize.height || doc.internal.pageSize.getHeight());
    const logoData = new Image()
    logoData.src = '../../../../../public/images/product/logo.jpg'
    //添加图片,参数依次为:imageData(string|HTMLImageElement|HTMLCanvasElement|Uint8Array),x(水平位置),y(垂直位置),w(宽),h(高)
    //位置、宽、高的单位都为mm
    doc.addImage(logoData, 10, 5, 21, 21)
    doc.setFontSize(38)//字体大小配置,在需要配置的文本上方设置。
    doc.setTextColor('red')//字体颜色配置
    //添加文本,参数为('文本内容',x,y)
    doc.text('this is a textContent', 35, 20)
    doc.setFontSize(15)
    doc.setTextColor('black')
    doc.text('this is a textContent too', 10, 35)
    doc.setLineWidth(0.5) //设置线条宽度
    doc.setDrawColor('red')//设置线条颜色
    //绘制线条(X1,Y1,X2,Y2)
    doc.line(5, 38, 205, 38)
    html2canvas(document.getElementById('chart-total'), {
        background: "#ffffff",
        dpi: 140
    }
    ).then((canvas: HTMLCanvasElement) => {
        doc.addImage(canvas, 10, 55, pageWidth - 30, pageHeight - 90)
        //新增一页
        doc.addPage()
        const data = [  { time: '202103011000', address: '上海' }, 
                        { time: '202103011000', address: '上海' },
                        { time: '202103011000', address: '上海' }
                    ]
        const header = [{ header: '时间', dataKey: 'time' }, { header: '地址', dataKey: 'address' }]
        doc.autoTable({
            body: data,
            columns: header,
            //表格全局样式
            styles: {
                fillColor: [255, 255, 255],//背景色
                font: 'simhei', //字体,如果不配置,中文仍会乱码
                textColor: [0, 0, 0],//字体颜色
                halign: 'center', // 文字水平布局left, center, right
                valign: 'middle',//垂直布局
            },
            //表头样式配置
            headStyles: {
                fillColor: [220, 220, 220],
                lineColor: 200,
                lineWidth: 0.5,
            },
            //列的样式,key值对应header的dataKey
            columnStyles: {
                'time': { columnWidth: 35 },
            },
            theme: 'grid',      // 主题
        })
        const pageSize = doc.getNumberOfPages()
        doc.setLineWidth(0.3)
        doc.setFontSize(12)
        //设置页脚
        for (let page = 1; page <= pageSize; page++) {
            doc.setPage(page)
            doc.setDrawColor('#f16c6c')
            doc.line(25, pageHeight - 10, pageWidth - 25, pageHeight - 10)
            doc.text('制作:某某某   审合:某某某  签发:某某某   电话:XXXXXXXXXXX', 40, pageHeight - 5)
        }
        doc.save(`${filename}.pdf`);
    })

}

2.生成word:

1.使用的插件:docxjs

docx的安装和API不同功能的案例demo此demo几乎包括了所有API的使用和配置。

2.demo
import {
    Document,
    TextRun,
    Footer,
    TabStopType,
    AlignmentType,
    TabStopPosition,
    VerticalPositionRelativeFrom,
    VerticalPositionAlign,
    HorizontalPositionRelativeFrom,
    HorizontalPositionAlign,
    Media,
    Packer,
    Paragraph,
} from "docx";

export function exportForecastWord(filename) {
    const doc = new Document();
    //页脚
    const footers = {
        default: new Footer({
            children: [new Paragraph({
                children: [new TextRun('电话:010-68400565'), new TextRun('\t传真:010-58991637 ')],
                //实现第一个text左对齐,第二个text右对齐
                tabStops: [
                    {
                        type: TabStopType.RIGHT,
                        position: TabStopPosition.MAX,
                    },
                ],
                border: {
                    top: { color: '000', value: 'dashed', size: 10, space: 5 }
                }
            })],
        }),
    }
    formUrlGetDataUrl('../public/images/logo.jpg', (dataUrl) => {
        const logoImge = Media.addImage(doc, dataUrl, 70, 70, {
            //设置float样式主要是为了让图片和其水平相邻的文字垂直居中,可以去掉对比效果
            floating: {
                zIndex: 5,
                horizontalPosition: {
                    relative: HorizontalPositionRelativeFrom.COLUMN,
                    align: HorizontalPositionAlign.LEFT,
                },
                verticalPosition: {
                    relative: VerticalPositionRelativeFrom.PARAGRAPH,
                    align: VerticalPositionAlign.CENTER,
                },
            },
        });   
        doc.addSection({
            children: [
                new Paragraph({
                    children: [logoImge, 
                            new TextRun({
                            text: "this is a wordTitle", 
                            bold: true,
                            color: "red",
                            size: 60})
                    ],
                    alignment: AlignmentType.RIGHT,
                    spacing: {
                        before: 150,
                        after: 150
                    }
                }),
            ],
            footers: footers
        });
        Packer.toBlob(doc).then(blob => {
            var a = document.createElement('a');
            a.href = URL.createObjectURL(blob);
            a.download = `${filename.replace(/\s/g, '')}.docx`
            setTimeout(function () {
                a.click();
                URL.revokeObjectURL(a.href);
                a = null
            }, 0);
        });
    })
}

/**
 * 根据图片路径得到dataurl
 * @param url 图片路径
 * @param cb 回调函数
 */
function formUrlGetDataUrl(url, cb) {
   var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    var img = new Image();
    img.src = url;
    img.onload = () => {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0);
        cb(canvas.toDataURL())
        canvas=null
    };
}

使用这个demo时需要注意:文件中使用了一个图片相对路径,所以需要在对应路径下添加一个图片。
补充1:doxcjs生成表格时单元格文本的水平垂直居中实现:

function docxTable(tableData:any[]){
	let data = removeNullData([...tableData])
	const rows = data.map((row ,rowIndex)=> {
		return new TableRow({
			children: row.map((col)=>{
				return new TableCell({
					children: [new Paragraph({ 
									children: [new TextRun({ text: String(col),size:20,bold:rowIndex===0?true:false })],
									alignment:AlignmentType.CENTER//文本水平居中
								})
							],
					verticalAlign: VerticalAlign.CENTER,
					margins: {
					//为文本上下设置相同的间距,实现垂直居中,默认文本和上下边界没有空白
						top: convertInchesToTwip(0.1),
						bottom: convertInchesToTwip(0.1),
						left: 0,
						right: 0,
					},
				})
			})
		})
	})
	return new Table({
		rows,
		width: {
			size: 100,
			type: WidthType.PERCENTAGE
		},
	});
}
const tableData=[['header1','header2'],['text1','text2']]

补充2:使用WPS打开生成的word文件部分格式不兼容问题解决:
1.包含表格时,如果设置width属性的type值为PERCENTAGE时,用WPS打开word文件,出现单元格width变窄的情况,
2.文本,border等设置的color未生效,显示都是黑色
解决:1. 可以不设置Table的width属性,如果需要固定表格的宽度可以设置Table或者TableCell的width属性的type值为WidthType.DXA

return new Table({
		rows,
		width: {
			size: 9000,
			type: WidthType.DXA
		},
	});

附上单位换算关系:参考
在这里插入图片描述

2.color的值不要设置为red等单词而要使用16进制数值,且前面不要加#

new Paragraph({
					children: [logoImge, new TextRun({
						text: "天气预报",
						bold: true,
						color: "fa0202",
						size: 60,

					})],
					alignment: AlignmentType.RIGHT,
					spacing: {
						before: 150,
						after: 150
					}
				}),
  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值