一个简洁高效的Markdown转PDF转换器,专注于HTML到PDF的转换过程,使用html2pdf.js库实现。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Markdown 转 PDF 转换器</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
line-height: 1.6;
color: #333;
background: linear-gradient(135deg, #4361ee, #3a0ca3);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
header {
text-align: center;
padding: 20px 0 30px;
color: white;
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
text-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.app-container {
background: white;
border-radius: 16px;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
overflow: hidden;
margin-bottom: 30px;
display: flex;
flex-direction: column;
min-height: 70vh;
}
.editor-preview {
display: flex;
min-height: 500px;
}
.editor-section, .preview-section {
padding: 25px;
min-height: 400px;
flex: 1;
}
.editor-section {
background: #f8f9fa;
border-right: 1px solid #e9ecef;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 12px;
border-bottom: 2px solid #4361ee;
}
.section-title {
font-size: 1.3rem;
color: #2b2d42;
font-weight: 600;
}
.word-count {
background: #4361ee;
color: white;
padding: 3px 12px;
border-radius: 20px;
font-size: 0.85rem;
font-weight: 500;
}
textarea {
width: 100%;
height: 400px;
padding: 20px;
font-family: 'Fira Code', monospace;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 10px;
resize: none;
box-shadow: inset 0 2px 6px rgba(0,0,0,0.05);
line-height: 1.7;
background: white;
}
textarea:focus {
outline: none;
border-color: #4895ef;
box-shadow: 0 0 0 3px rgba(72, 149, 239, 0.2);
}
#preview {
height: 400px;
padding: 20px;
overflow-y: auto;
border: 1px solid #e9ecef;
border-radius: 10px;
background: white;
font-size: 16px;
line-height: 1.8;
box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);
}
#preview h1,
#preview h2,
#preview h3 {
margin: 1.2em 0 0.8em;
color: #2b2d42;
padding-bottom: 0.3em;
border-bottom: 1px solid #eee;
}
#preview h1 {
color: #4361ee;
border-bottom: 2px solid #4361ee;
}
#preview p {
margin: 1em 0;
}
#preview pre {
background: #2b2d42;
color: #f8f9fa;
padding: 15px;
border-radius: 8px;
overflow-x: auto;
margin: 1.5em 0;
}
#preview code {
font-family: 'Fira Code', monospace;
background: rgba(67, 97, 238, 0.1);
padding: 2px 6px;
border-radius: 4px;
font-size: 0.95em;
color: #e63946;
}
.controls {
display: flex;
gap: 15px;
margin-top: 20px;
padding: 0 25px 25px;
}
.btn {
padding: 15px 25px;
font-size: 1.1rem;
border: none;
border-radius: 10px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 600;
display: flex;
align-items: center;
gap: 12px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.btn i {
font-size: 1.3em;
}
.btn-primary {
background: linear-gradient(to right, #4361ee, #3f37c9);
color: white;
}
.btn-pdf {
background: linear-gradient(to right, #e63946, #c1121f);
color: white;
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 15px rgba(0,0,0,0.15);
}
.pdf-settings {
display: flex;
gap: 15px;
margin-top: 15px;
background: #f8f9fa;
padding: 20px;
border-radius: 10px;
border-top: 1px solid #e9ecef;
}
.setting-group {
display: flex;
flex-direction: column;
gap: 8px;
flex: 1;
}
.setting-group label {
font-weight: 500;
color: #2b2d42;
font-size: 0.95rem;
}
select, input {
padding: 12px 15px;
border: 1px solid #ced4da;
border-radius: 8px;
font-size: 1rem;
background: white;
}
.notification {
position: fixed;
top: 25px;
right: 25px;
padding: 18px 28px;
background: #2a9d8f;
color: white;
border-radius: 12px;
box-shadow: 0 8px 20px rgba(0,0,0,0.2);
transform: translateX(200%);
transition: transform 0.4s ease;
z-index: 1000;
display: flex;
align-items: center;
gap: 15px;
font-size: 1.1rem;
}
.notification.show {
transform: translateX(0);
}
.notification i {
font-size: 1.8rem;
}
footer {
text-align: center;
color: white;
padding: 20px 0;
font-size: 1rem;
}
@media (max-width: 768px) {
.editor-preview {
flex-direction: column;
}
.editor-section {
border-right: none;
border-bottom: 1px solid #e9ecef;
}
.pdf-settings {
flex-direction: column;
}
h1 {
font-size: 2rem;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>Markdown 转 PDF 转换器</h1>
<p>在浏览器中直接转换Markdown为PDF文档</p>
</header>
<div class="app-container">
<div class="editor-preview">
<div class="editor-section">
<div class="section-header">
<h2 class="section-title">
<span>Markdown 编辑器</span>
<span class="word-count" id="word-count">0 字</span>
</h2>
</div>
<textarea id="markdown-input" placeholder="在此输入Markdown文本..."># Markdown 转 PDF 示例
## 核心功能演示
此工具使用 **html2pdf.js** 将HTML内容转换为PDF文档,完全在浏览器中运行。
### 主要特点
- 100% 客户端转换(无服务器交互)
- 支持自定义页面设置
- 实时Markdown预览
- 简单易用的界面
### 代码示例
```javascript
// 核心转换函数
function generatePDF() {
const element = document.getElementById('preview');
const options = {
margin: [10, 10, 10, 10],
filename: 'document.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
};
html2pdf().set(options).from(element).save();
}
转换过程说明
将Markdown转换为HTML
使用html2pdf.js处理HTML元素
生成PDF文件并下载
提示:所有处理都在您的浏览器中完成,确保隐私安全</textarea>
</div>
<div class="preview-section">
<div class="section-header">
<h2 class="section-title">
<span>PDF 预览</span>
</h2>
</div>
<div id="preview"></div>
</div>
</div>
<div class="pdf-settings">
<div class="setting-group">
<label for="page-size">页面尺寸:</label>
<select id="page-size">
<option value="a4">A4 (210×297mm)</option>
<option value="letter">Letter (216×279mm)</option>
<option value="legal">Legal (216×356mm)</option>
</select>
</div>
<div class="setting-group">
<label for="page-orientation">页面方向:</label>
<select id="page-orientation">
<option value="portrait">纵向</option>
<option value="landscape">横向</option>
</select>
</div>
<div class="setting-group">
<label for="filename">文件名:</label>
<input type="text" id="filename" value="markdown-document" placeholder="输入文件名">
</div>
</div>
<div class="controls">
<button id="download-pdf" class="btn btn-pdf">
<i class="fas fa-file-pdf"></i>
<span>生成并下载PDF</span>
</button>
<button id="clear-btn" class="btn">
<i class="fas fa-trash-alt"></i>
<span>清空内容</span>
</button>
<button id="example-btn" class="btn btn-primary">
<i class="fas fa-file-code"></i>
<span>加载示例</span>
</button>
</div>
</div>
<footer>
<p>© 2023 Markdown 转 PDF 转换器 | 完全在浏览器端运行</p>
</footer>
</div>
<div class="notification" id="notification">
<i class="fas fa-check-circle"></i>
<span>PDF文档已成功生成并下载!</span>
</div>
<script>
// 获取DOM元素
const markdownInput = document.getElementById('markdown-input');
const preview = document.getElementById('preview');
const downloadPdfBtn = document.getElementById('download-pdf');
const clearBtn = document.getElementById('clear-btn');
const exampleBtn = document.getElementById('example-btn');
const wordCount = document.getElementById('word-count');
const notification = document.getElementById('notification');
const pageSizeSelect = document.getElementById('page-size');
const pageOrientationSelect = document.getElementById('page-orientation');
const filenameInput = document.getElementById('filename');
// 配置marked
marked.setOptions({
breaks: true,
gfm: true
});
// 初始渲染
updatePreview();
updateStats();
// 输入时更新预览
markdownInput.addEventListener('input', function() {
updatePreview();
updateStats();
});
// 更新预览函数
function updatePreview() {
const markdownText = markdownInput.value;
preview.innerHTML = marked.parse(markdownText);
}
// 更新统计信息
function updateStats() {
const text = markdownInput.value;
const words = text.trim() === '' ? 0 : text.trim().split(/\s+/).length;
wordCount.textContent = words + ' 字';
}
// 核心功能:HTML转PDF
function generatePDF() {
const element = preview;
const options = {
margin: [10, 10, 10, 10],
filename: filenameInput.value + '.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 2,
useCORS: true,
letterRendering: true
},
jsPDF: {
unit: 'mm',
format: pageSizeSelect.value,
orientation: pageOrientationSelect.value
}
};
// 显示生成中的提示
downloadPdfBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 生成中...';
downloadPdfBtn.disabled = true;
// 生成PDF
html2pdf().set(options).from(element).save().then(() => {
// 显示成功通知
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
}, 3000);
// 恢复按钮状态
downloadPdfBtn.innerHTML = '<i class="fas fa-file-pdf"></i> 生成并下载PDF';
downloadPdfBtn.disabled = false;
});
}
// 事件监听
downloadPdfBtn.addEventListener('click', generatePDF);
clearBtn.addEventListener('click', function() {
markdownInput.value = '';
updatePreview();
updateStats();
});
exampleBtn.addEventListener('click', function() {
markdownInput.value = `# 示例文档
HTML 转 PDF 实现
这个示例展示了如何将HTML内容转换为PDF文档:
技术要点
使用 html2pdf.js 库实现转换
完全在浏览器端完成
支持自定义页面设置
无需服务器处理
转换代码
\`\`\`javascript
function convertToPDF() {
const element = document.getElementById('content');
const options = {
margin: 10,
filename: 'document.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
};
html2pdf().set(options).from(element).save();
}
\`\`\`
使用说明
在编辑区编写Markdown内容
调整PDF设置(页面尺寸、方向等)
点击"生成并下载PDF"按钮
查看生成的PDF文件
注意:所有处理都在您的浏览器中完成,确保数据安全`;
updatePreview();
updateStats();
});
</script>
</body> </html>