封装markdown转html,导出PDF功能(解决文字被隔断,符号挤压问题)

53 阅读1分钟

模块文件

import MarkdownIt from 'markdown-it'
import html2pdf from 'html2pdf.js'
/* ========== . 构造“防截断”markdown-it 实例 ========== */
const markdown = new MarkdownIt({
	breaks: true
})

/** 安全地给 markdown-it 某条规则追加 class */
function addClassToRule(md, ruleName, cls) {


	const original = md.renderer.rules[ruleName] || function(tokens, idx, options, env, renderer) {
		return renderer.renderToken(tokens, idx, options)
	}
	md.renderer.rules[ruleName] = function(tokens, idx, options, env, renderer) {
		const token = tokens[idx]
		const old = token.attrGet('class') || ''
		token.attrSet('class', `${old} ${cls}`.trim())
		return original(tokens, idx, options, env, renderer)
	}
}



// 给以下元素添加 pdf-safe 类:防止分页隔断
// <p>(段落)
// <h1>~<h6>(标题)
// <li>(列表项)
// <blockquote>(引用块)
// <tr>(表格行)

[
	'paragraph_open',
	'heading_open',
	'list_item_open',
	'blockquote_open',
	'tr_open'
].forEach(rule => addClassToRule(markdown, rule, 'pdf-safe'))


// 给代码块页也添加pdf-safe 类
const originalFence = markdown.renderer.rules.fence || function(tokens, idx, options, env, renderer) {
	return renderer.renderToken(tokens, idx, options) // 这行其实不会走到,因为 fence 有默认实现
}

markdown.renderer.rules.fence = function(tokens, idx, ...args) {
	const raw = originalFence(tokens, idx, ...args)
	return `<div class="pdf-safe">${raw}</div>`
}

const unicodeMap = {
	':': ':',
	'(': '(',
	')': ')',

};

// 替换文本中的冒号和括号避免显示异常
const resultReplace = (text) => {
	let result = text.replace(/[\uff1a\uff08\uff09]/g, (match) => {
		return unicodeMap[match];
	});
	return result;
};


// 导出展示html的方法
export const showHtml = (value) => {
	return resultReplace(markdown.render(value))
}


/* ==========  导出 PDF ========== */
export const exportPDF = async (element, fileName) => {


	/* 如果表格太宽,强制不换行(可选) */
	element.querySelectorAll('table').forEach(t => {
		t.style.tableLayout = 'fixed'
		t.style.width = '100%'
	})

	const opt = {
		margin: 10,
		filename: `${fileName}.pdf`,
		image: {
			type: 'jpeg',
			quality: 0.98
		},
		html2canvas: {
			scale: 2,
			useCORS: true
		},
		jsPDF: {
			unit: 'mm',
			format: 'a4',
			orientation: 'portrait'
		}
	}

	await html2pdf().set(opt).from(element).save()
}

使用方法

<template>
   <div id="pdfArea" style="white-space: pre-wrap;overflow-y: auto; "
					v-html="showHtml(content)">

    </div>
    	<button @click="ExportPDF">导出为PDF</button>
</template>
        import {
		ref,
	} from 'vue'

	import {
		exportPDF,showHtml
	} from '@/tools/methods' //依据自己模块所在路径
        
        
  const content = ref('')
	const topic = ref('')
        
        //模拟获取markdown内容
   const fetchDetail = async () => {
		let data = JSON.parse(localStorage.getItem('talentMark'))

		content.value = data.md_tmp_file
		topic.value = data.name //生成的文件名
	}
	fetchDetail()
        
        
      
	const ExportPDF = async () => {


		const element = document.getElementById('pdfArea')

		exportPDF(element, topic.value)


	}
        
        
        

main.scss

.pdf-safe {
		page-break-inside: avoid;//**避免内容被分页打断**
	}