文章目录
1. pdf 相关
1.1 html2Canvas、JsPDF分页打印
- 安装包
html2canvas jspdf
该应用场景是,是使用luckysheet生成PDF,一共分了四种情况,传值的时候只需要判断,生成html的宽度(需要乘0.75,因为是pt单位做对比)只要大于a4的宽度就需要纵向打印,jspdf在线demo戳这里,api文档戳这里
- 单张纵向a4
- 单张横向a4
- 分页纵向a4
- 分页横向a4
- 这四种都可以识别
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
/**
* 导出页面为PDF格式,1pt === 4/3px,1px === 0.75pt
* @param { String } title 文件名
* @param { Number } type 0:生成PDF、1:生成base64
* @param { Boolean } longitudinalShow true:横向打印,false:纵向打印
* @returns { Promise }
*/
export function getPdf(title, type, longitudinalShow = false) {
return new Promise((res, rej) => {
html2Canvas(document.querySelector('#printHtml'), {
allowTaint: true, // 是否允许不同源的图片污染画布
taintTest: false, // 是否在渲染前测试图片
useCORS: true, // 是否尝试使用 CORS 从服务器加载图片
dpi: window.devicePixelRatio * 1, // 将分辨率提高到特定的DPI
scale: 1, // 用于渲染的比例,默认为浏览器设备像素比率
}).then((canvas) => {
// a4纸 pt尺寸
let a4Size = {
w: 595.28,
h: 841.89,
};
// 算的是 px单位需要转 pt,a4纸与当前canvas的间距,用于居中
let l = (((longitudinalShow ? a4Size.h : a4Size.w) * 1.33 - canvas.width) / 2) * 0.75;
let pageData = canvas.toDataURL('image/jpeg', 1.0);
let PDF = new JsPDF({
// landscape:横向打印,默认纵向打印
orientation: longitudinalShow ? 'landscape' : '',
unit: 'pt',
format: 'a4',
});
// 表高度,pt单位比较
let sheetHeight = canvas.height * 0.75;
let t = 0;
// 是否需要转换宽高(a4纸打印做转向了,但是分页处理没有转向)
let isRotate = longitudinalShow ? a4Size.w : a4Size.h;
// 当表小于a4的高时,无需分页
if (isRotate > sheetHeight) {
/*
addImage(img, JPEG, left, top, width, height) pt单位
1. 宽高传0,默认为原始图片的px单位
2. 如果传入图片原始宽高会识别为pt,打印出来后会进行1.333倍的放大
3. 打个比方a4纸的宽pt单位为595.28,px单位为793.71,一个图片宽高为180px
如果使用默认为0的,打印出来还是为180px,如果手动设置180,打印出来就会转换为240px
意思就是如果图片原始为px单位,设置的pt单位打印就不需要传,如果图片原始为pt单位,设置的pt单位打印就需要传
*/
PDF.addImage(pageData, 'JPEG', l, 24, 0, 0);
} else {
while (sheetHeight > 0) {
PDF.addImage(pageData, 'JPEG', l, t, 0, 0);
sheetHeight -= isRotate;
t -= isRotate;
// 避免添加空白页
if (sheetHeight > 0) {
PDF.addPage();
}
}
}
if (!type) {
PDF.save(title + '.pdf');
} else {
var basePDf = PDF.output('datauristring');
res(basePDf);
}
});
});
}
1.2 pdfmake
- 安装包
pdfmake html-to-pdfmake
这种场景我是确认了就是 a4 的宽度,所以没有做过多的配置,官网戳这里
注:这里要特别说一下,关于打印 pdf 中文乱码的问题,pdfmake 本身就没有去适配中文的字体,用的都是 Roboto 字体,所以要去官网拉原本的项目,重新添加中文字体然后打包,替换
pdfmake/build/vfs_fonts.js
文件,项目地址戳这里
- 在该项目
examples/fonts
目录下移入一个中文字体包(.ttf 文件)- 使用
npm run build:vfs
命令在 build 下生成vfs_fonts.js
文件- 如果
npm run build:vfs
报错,需要先执行npm run build:fonts
在执行npm run build:vfs
- 拿到
vfs_fonts.js
文件,替换自己项目中的文件(自己项目中的文件在哪里,ctrl+鼠标左键 导的包,可以直接跳到包的位置)- 不要直接替换文件,打包后的文件和之前的不一样,只需要替换 vfs 对象中的内容就可以了
- 修改 node_modules 中的文件后,需要重新运行项目
// pdfmake 数据格式导出pdf
const pdfMake = require('pdfmake/build/pdfmake');
// pdfmake 导出的 fonts 字体
const pdfFonts = require('pdfmake/build/vfs_fonts');
pdfMake.vfs = pdfFonts.pdfMake.vfs;
// 将 HTML 转 Pdfmake 数据格式
const htmlToPdfmake = require('html-to-pdfmake');
// 配置字体
pdfMake.fonts = {
Roboto: {
bold: "Roboto-Medium.ttf",
bolditalics: "Roboto-MediumItalic.ttf",
italics: "Roboto-Italic.ttf",
normal: "Roboto-Regular.ttf",
},
// 中文字体
msyh: {
normal: "msyh.ttf",
bold: "msyh.ttf",
italics: "msyh.ttf",
bolditalics: "msyh.ttf",
},
};
pdfMake
.createPdf({
// 默认使用中文字体
defaultStyle: {
font: "msyh",
},
content: htmlToPdfmake(`我是html数据结构`), // 需要转换成 pdfmake 识别的数据结构
})
// pdfMake.createPdf() 原型上有获取base64的方法
.download();
1.3 vue-html2pdf 对 vue2 的项目进行导出
- 安装包
vue-html2pdf
这个库的功能也是非常强大的,但是只适用于 vue2,配置文档和 demo 可以直接在 npm 搜对应的包
<vue-html2pdf
:show-layout="false"
:float-layout="true"
:enable-download="true"
:preview-modal="true"
:paginate-elements-by-height="1400"
filename="hee hee"
:pdf-quality="2"
:manual-pagination="false"
pdf-format="a4"
pdf-orientation="landscape"
pdf-content-width="800px"
@progress="onProgress($event)"
@hasStartedGeneration="hasStartedGeneration()"
@hasGenerated="hasGenerated($event)"
ref="html2Pdf"
>
<section slot="pdf-content">
<!-- PDF 对应要导出的 html 内容 -->
</section>
</vue-html2pdf>
// 调用该方法生成 pdf
this.$refs.html2Pdf.generatePdf()
这里简单汇总一下上面几种方案
- jspdf 是属于打印,可以控制清晰度、百分比等,如果只是做预览的话建议使用这个,对框架也没有什么要求
- pdfmake 是属于解析 html 元素,在处理成 pdf,对预览效果不是很好,很可能达不到想要的效果,但是可以保存超链接,如果是功能类的建议使用这个,对框架没什么要求
- vue-html2pdf 这种挺强大的,上面两个的优点都保留(这个没用过,还不知道有什么坑),但是只能 vue2 项目可以用,这点比较坑,使用 vue2 项目开发的可以试试这个,上手比较简单
2. word 相关
2.1 html 导出 word
- 安装包
jquery file-saver
// 导入下面的 js 文件就可以了
$("html元素").wordExport('测试world');
// 导入 js 文件
import saveAs from "file-saver";
if (typeof $ !== "undefined" && typeof saveAs !== "undefined") {
(function ($) {
$.fn.wordExport = function (fileName) {
fileName = typeof fileName !== "undefined" ? fileName : "jQuery-Word-Export";
var statics = {
mhtml: {
top:
"Mime-Version: 1.0\nContent-Base: " +
location.href +
'\nContent-Type: Multipart/related; boundary="NEXT.ITEM-BOUNDARY";type="text/html"\n\n--NEXT.ITEM-BOUNDARY\nContent-Type: text/html; charset="utf-8"\nContent-Location: ' +
location.href +
"\n\n<!DOCTYPE html>\n<html>\n_html_</html>",
head: '<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n<style>\n_styles_\n</style>\n</head>\n',
body: "<body>_body_</body>",
},
};
var options = {
maxWidth: 624,
};
// Clone selected element before manipulating it
var markup = $(this).clone();
// Remove hidden elements from the output
markup.each(function () {
var self = $(this);
if (self.is(":hidden")) self.remove();
});
// Embed all images using Data URLs
var images = Array();
var img = markup.find("img");
for (var i = 0; i < img.length; i++) {
// Calculate dimensions of output image
var w = Math.min(img[i].width, options.maxWidth);
var h = img[i].height * (w / img[i].width);
// Create canvas for converting image to data URL
var canvas = document.createElement("CANVAS");
canvas.width = w;
canvas.height = h;
// Draw image to canvas
var context = canvas.getContext("2d");
context.drawImage(img[i], 0, 0, w, h);
// Get data URL encoding of image
var uri = canvas.toDataURL("image/png/jpg");
$(img[i]).attr("src", img[i].src);
img[i].width = w;
img[i].height = h;
// Save encoded image to array
images[i] = {
type: uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")),
encoding: uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")),
location: $(img[i]).attr("src"),
data: uri.substring(uri.indexOf(",") + 1),
};
}
// Prepare bottom of mhtml file with image data
var mhtmlBottom = "\n";
for (var j = 0; j < images.length; j++) {
mhtmlBottom += "--NEXT.ITEM-BOUNDARY\n";
mhtmlBottom += "Content-Location: " + images[j].location + "\n";
mhtmlBottom += "Content-Type: " + images[j].type + "\n";
mhtmlBottom += "Content-Transfer-Encoding: " + images[j].encoding + "\n\n";
mhtmlBottom += images[j].data + "\n\n";
}
mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";
//TODO: load css from included stylesheet
var str = '<head><meta charset="utf-8"></meta>',
styles = document.querySelectorAll("style");
for (var n = 0; n < styles.length; n++) {
str += styles[n].outerHTML;
}
str +=
"<style>table tr td{padding-left:5px;padding-right:5px}.tdTitle{background:#c2c1c1}.spaceRow{margin-top:10px;}table{width:100%;}</style>";
str += "<style>table{border-collapse: collapse;table-layout: fixed}</style>";
str +=
"<style>table td,th{ height:30px;font-size:14px;border-width:1px;border-style: solid;border-color: #000;word-break: keep-all;}</style>";
str += "</head>";
// Aggregate parts of the file together
var fileContent =
statics.mhtml.top.replace(
"_html_",
statics.mhtml.head.replace("_styles_", str) +
statics.mhtml.body.replace("_body_", markup.html())
) + mhtmlBottom;
// Create a Blob with the file contents
var blob = new Blob([fileContent], {
type: "application/msword;charset=utf-8",
});
saveAs(blob, fileName + ".doc");
};
})($);
} else {
if (typeof $ === "undefined") {
console.error("jQuery Word Export: missing dependency (jQuery)");
}
if (typeof saveAs === "undefined") {
console.error("jQuery Word Export: missing dependency (FileSaver.js)");
}
}
3. html 相关
3.1 word 转 html
- 安装包
import mammoth from "mammoth"
用法比较简单,但是有一个问题就是表格边框会丢失,npm 上也提到过了
const file = filexxx; // 获取选择的文件
const reader = new FileReader();
reader.readAsArrayBuffer(file); // 将文件读取为字节数组
reader.onload = () => {
const arrayBuffer = reader.result;
mammoth
.convertToHtml({ arrayBuffer })
.then((result) => {
const html = result.value; // 返回 html
})
.done();
};