原文链接
欢迎大家对于本站的访问 - AsterCasc
前言
最近整理的文档比较多,手写的话比较习惯markdown
,但由于其中一大部分需要提供给对接方,所以转换成Html
以及Pdf
就是需要处理的部分了。这种流程在线工具比较多,但是一来很多有次数限制(有一说一,对于涉及服务端资源的有次数限制很正常,但是很多这种纯Web
端的任务流有次数限制我不理解),二来以备不时之需,我们可以需要搭一个简易的转换平台。如果文档转换量不大,可以参考使用markdowntopdf。当然可以也使用一些markdonwn
的客户端编辑器,很多都带有这个功能,比如Obisian
等
再次重申,站长非前端工程师,本站所有前端代码仅供参考,该工具已部署到本站工具箱中,需要小伙伴可以参考
实现
这里我们借助一些工具包,就不手动造轮子了,目前考虑使用人数比较多、相对比较好用的包markdown-it
、marked
、jspdf
,pdfmake
以及他们的一些衍生包,本站的文章渲染就是使用的marked
,可以参考相关源码,同时也可以参考本站文章Marked.js渲染下md内图片点击放大解决方案。对于marked
和markdown-it
,marked
的使用人数要稍多一些,社区会更活跃,但是相差地不是特别多,而markdown-it
可以定制的选项相比marked
更多,拓展性以及自定义性会更强,相对易用性会差一点
由于我们之前使用的是marked
,这里我们就以markdonw-it
进行文档举例,具体本站自己的工具实现还是采用marked
Markdown转Html
markdown-it
markdown-it包引用
"dependencies": {
"markdown-it": "^14.1.0",
}
markdown-it-github
markdown-it使用
一般当我们不考虑在后面转Pdf
的话,一般的处理方式是引用highlight.js
进行代码渲染,然后再定义基础类的渲染,比如your_parent_class pre code {}
相关及以下的渲染,基本示例如下:
import hljs from "highlight.js";
import markdownit from 'markdown-it'
const md = markdownit('default', {
html: true,
linkify: true,
typographer: true,
langPrefix: 'hljs language-',
highlight: (code, lang) => {
//correct
lang = lang === 'mysql' ? 'sql' : lang
lang = lang === 'sh' ? 'powershell' : lang
lang = lang === 'shell' ? 'powershell' : lang
//convert
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, {language}).value;
}
})
const ret = md.render("## something")
如果你使用的是marked
,基本示例如下:
import {marked} from "marked";
import {markedHighlight} from "marked-highlight";
import hljs from "highlight.js";
import {gfmHeadingId} from "marked-gfm-heading-id";
marked.use(markedHighlight({
langPrefix: 'hljs language-',
highlight(code, lang) {
//correct
lang = lang === 'mysql' ? 'sql' : lang
lang = lang === 'sh' ? 'powershell' : lang
lang = lang === 'shell' ? 'powershell' : lang
//convert
const language = hljs.getLanguage(lang) ? lang : 'plaintext';
return hljs.highlight(code, {language}).value;
}
}));
marked.use(gfmHeadingId({}));
marked.use({
mangle: false,
headerIds: false
});
const ret = marked.parse("## something ")
但是由于独立导出Html
以及Pdf
的需求,我们这里需要对于标签进行直接注入式地渲染,以markdown-it
为例,如果我们需要渲染标题为绿色,处理方案为:
const md = markdownit('default', {
html: true,
linkify: true,
typographer: true,
})
md.renderer.rules.heading_open = (tokens, idx) => {
return '<' + tokens[idx].tag + ' style="color: green; font-size: 24px;">';
};
const ret = md.render("## 前言");
这里可以根据tokens
和idx
进行标签定位,更丰富地渲染导出的Html
。更多标签选项,比如code
,hr
,table
,可以参考renderer以及rules_block
如果你使用的是marked
对于不同标签的渲染,大概形式为:
const renderer = {
heading(text, level) {
if (level === 2) {
return `<h${level} style="color: red;">${text}</h${level}>`
} else {
return `<h${level} style="color: blue;">${text}</h${level}>`
}
},
};
marked.use({renderer})
更多marked
不同标签的渲染函数可以参考marked-render
样式内嵌渲染
我们在引用其他渲染包的时候,比如highlight.js
这种,我们会发现他们的渲染逻辑是基于类的,但是后续转PDF
或者直接导出html
文件是无法直接处理class
文件的。所以如果小伙伴们有需求,是需要对于生成的html
进行css
整合的,将渲染直接内嵌到元素当中。这里我们可以选择已有的工具包进行处理,juice
或者inline-css
都可以,这里我们以juice
举例
首先写一个样式文件,如果你使用highlight.js
,可以在highlightjs-style中选择一个喜欢的样式,然后在node_modules/highlight.js/styles/
将他拷贝出来,创建自己导出样式文件,然后再在上面做修改,大概类似于:
/*code style*/
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em
}
code.hljs {
padding: 3px 5px
}
.hljs-comment, .hljs-meta {
color: #9699a3
}
.hljs-deletion, .hljs-doctag, .hljs-regexp, .hljs-selector-attr, .hljs-selector-class, .hljs-selector-id, .hljs-selector-pseudo, .hljs-tag, .hljs-template-tag, .hljs-variable.language_ {
color: #8c4351
}
.hljs-link, .hljs-literal, .hljs-number, .hljs-params, .hljs-template-variable, .hljs-type, .hljs-variable {
color: #965027
}
.hljs-attribute, .hljs-built_in {
color: #8f5e15
}
.hljs-keyword, .hljs-property, .hljs-subst, .hljs-title, .hljs-title.class_, .hljs-title.class_.inherited__, .hljs-title.function_ {
color: #0f4b6e
}
.hljs-selector-tag {
color: #33635c
}
.hljs-addition, .hljs-bullet, .hljs-quote, .hljs-string, .hljs-symbol {
color: #485e30
}
.hljs-code, .hljs-formula, .hljs-section {
color: #34548a
}
.hljs-attr, .hljs-char.escape_, .hljs-keyword, .hljs-name, .hljs-operator {
color: #5a4a78
}
.hljs-punctuation {
color: #343b58
}
.hljs {
background: white;
color: #565a6e
}
.hljs-emphasis {
font-style: italic
}
.hljs-strong {
font-weight: 700
}
/*your else style*/
p {
color: green;
}
然后我们利用raw-loader.js
将样式从文件中读入,再利用juice
重新渲染html
文件即可:
import juice from 'juice';
import markdownCss from '!!raw-loader!@/styles/output-pdf.css';
let inputMarkdown = ref("")
function render() {
htmlRet.value = marked.parse(inputMarkdown.value)
htmlRet.value = juice(htmlRet.value, {
extraCss: markdownCss
})
//...
}
Html转Pdf
对于Pdf
的转换,我们一般处理是,先转Html
然后再转Pdf
,直接转Pdf
的包没有特别好用的,主要是对于表格等特殊元素的支持较差,比如propra-tech/mdpdfmake或者patricsteiner/mdpdfmake。如果小伙伴们有什么比较好用的可以直接转的浏览器可用的工具包,可以在下方留言分享。Html
转Pdf
的主要的转换方式有两种使用jspdf
,或者使用pdfmake
搭配html-to-pdfmake
,我们这里选择后者,虽然两者都需要导入字体,但是jspdf
更难用一些,在导入字体后还需要配置页面大小,字间距等,如果不配置几乎用不了,而且目前版本非常难用,可以参考html method can’t handle Chinese correctly, even after used the .setFont method.,jsPDF.html output very large fields in document.等issues
。总之,虽然jspdf
只有一个包,但是对于Html
的转换是做地非常粗糙的
pdfmake
pdfmake包引用
"dependencies": {
"html-to-pdfmake": "^2.5.7",
"pdfmake": "^0.2.10",
}
pdfmake-github、html-to-pdfmake-github
pdfmake使用
由于浏览器和Pdf
对于字体的支持并不兼容,比如Pdf
并不能直接支持woff2。所以我们在转换器单独设定可用的字体,当然可以使用pdfmake
的默认字体,但是默认字体基本对于非英文字符都不支持。我们这里可以下载一个自己喜欢的字体,然后转Base64
,加载进pdfmake
即可,具体操作步骤为:
- 选择字体可以在任意字体网站上下载,注意商业条款和中文特殊字符的加入弄问题。比较方便的话也可以在GoogleFont中选择,可以下载字体包的包括
Black
、Light
、Bold
版本后续注入pdfmake
- 转
Base64
,这个随便搜一下font convert base64
或者file convert base64
或者base64-encode
啥的能出来一堆,由于这种网站很多都不稳定我这里就不直接摆链接了 - 创建字体资源,创建一个
your_font_name_data.js
之类的文件,然后在其中写入类似下方代码,因为一般字体包都不止一个字体文件,将名称和Base64
对应即可,当然如果你不需要Pdf
更丰富的字体显示,只写一个也没有问题export const yourFontNameVfs = { "YourFontName-Regular.ttf": "Regular-base64", "YourFontName-Bold.ttf": "Bold-base64", "YourFontName-Italics.tff": "Italics-base64", "YourFontName-BoldItalics.tff": "BoldItalics-base64", }
- 最后注入以及使用示例:
import htmlToPdfmake from 'html-to-pdfmake'; import pdfMake from 'pdfmake/build/pdfmake'; import {yourFontNameVfs} from '@/your_path/your_font_name_data' pdfMake.vfs = yourFontNameVfs; pdfMake.fonts = { //如果你只创建一个字体资源,那么可以将所有类型都指向改资源即可 YourFontName: { normal: 'YourFontName-Regular.ttf', bold: 'YourFontName-Bold.ttf', italics: 'YourFontName-Italics.tff', bolditalics: 'YourFontName-BoldItalics.tff', }, } let dataText = htmlToPdfmake("<div><h1 style='background-color: #2B5853'>数据类型</h1> <p>数据类型数据类型</p> </div>"); const docDefinition = { content: dataText, defaultStyle: { font: 'YourFontName' } }; const pdfDocGenerator = pdfMake.createPdf(docDefinition); pdfDocGenerator.download('document.pdf');
这里我们就可以完成从Html
到Pdf
的转换了,当然我们可以简单定义一些自己样式比如,背景色,字体颜色,页边距,方向等,这里大家参考官方文档自行定义即可
Tips:这里字体设置其实有个更简单的方法,直接使用URL
链接注入,不需要自己创建字体资源了:
pdfMake.fonts = {
YourFontName: {
normal: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-Regular.ttf',
bold: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-Medium.ttf',
italics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-Italic.ttf',
bolditalics: 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.4/fonts/Roboto/Roboto-MediumItalic.ttf',
}
}
但是我没有找到合适的支持ttf
且支持中文的库,谷歌的库只支持对外提供woff2
链接,比如M PLUS Rounded 1c,或者不支持中文字体,类似google-webfonts.ttf.css,如果有找到合适在线字体库的小伙伴可以在下方留言分享
原文链接
欢迎大家对于本站的访问 - AsterCasc