有一个markdown格式的文档,手头只有notepad++的MarkdownPanel插件可以预览,但是只能预览,不能直接转换为html文件下载,直接复制预览的内效果又不太好,度娘也能找到很多工具,但是都需要在线使用。所以考虑用AI自己生成一个。
要求:可以离线使用,轻量,可以实时预览。
了解到marked.js是一个使用JavaScript实现的markdown解析库,功能比较完善,所以考虑使用html+js来实现markdown文档转换为html功能。
生成结果截图:
以下为生成步骤及最终源码:
1.在deepseek中输入要求:
使用html+marked.js实现Markdown转html功能,要求页面为左右布局,左侧输入markdown文本后右侧可以实时预览,预览效果应与下载的html页面打开后的展示内容一致
2.检查deepseek生成的代码,发现deepseek生成的源码中有两部分不是以源码的形式输出的,输出的是渲染后的结果
发现把示例代码中的引用快'''全部调整成了\'\'\',源码复制出来时候稍后手动修正
4.新增上传功能,以及调整按钮布局
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Markdown实时预览工具</title>
<script src="marked.min.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333;
background-color: #f5f5f5;
height: 100vh;
display: flex;
flex-direction: column;
}
.header {
background-color: #2c3e50;
color: white;
padding: 15px 20px;
text-align: center;
}
.container {
display: flex;
flex: 1;
overflow: hidden;
}
.editor-pane, .preview-pane {
flex: 1;
padding: 20px;
overflow-y: auto;
height: 100%;
}
.editor-pane {
background-color: #f8f9fa;
border-right: 1px solid #ddd;
}
.preview-pane {
background-color: white;
}
textarea {
width: 100%;
height: 100%;
min-height: 300px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
resize: none;
font-family: monospace;
font-size: 14px;
line-height: 1.5;
}
.preview-content {
height: 100%;
overflow-y: auto;
padding: 10px;
}
.toolbar {
padding: 10px 20px;
background-color: #ecf0f1;
border-bottom: 1px solid #ddd;
display: flex;
justify-content: space-between;
}
.left-toolbar, .right-toolbar {
display: flex;
gap: 10px;
}
button {
padding: 8px 15px;
background-color: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background-color: #2980b9;
}
#file-input {
display: none;
}
/* Markdown样式,确保预览和导出一致 */
.markdown-body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333;
}
.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: 600;
line-height: 1.25;
}
.markdown-body h1 {
padding-bottom: 0.3em;
font-size: 2em;
border-bottom: 1px solid #eaecef;
}
.markdown-body h2 {
padding-bottom: 0.3em;
font-size: 1.5em;
border-bottom: 1px solid #eaecef;
}
.markdown-body p {
margin-top: 0;
margin-bottom: 16px;
}
.markdown-body a {
color: #0366d6;
text-decoration: none;
}
.markdown-body a:hover {
text-decoration: underline;
}
.markdown-body code {
font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27, 31, 35, 0.05);
border-radius: 3px;
}
.markdown-body pre {
background-color: #f6f8fa;
border-radius: 3px;
padding: 16px;
overflow: auto;
line-height: 1.45;
}
.markdown-body pre code {
padding: 0;
margin: 0;
background-color: transparent;
border-radius: 0;
}
.markdown-body blockquote {
padding: 0 1em;
color: #6a737d;
border-left: 0.25em solid #dfe2e5;
margin: 0 0 16px 0;
}
.markdown-body table {
border-collapse: collapse;
margin: 16px 0;
width: 100%;
}
.markdown-body table th, .markdown-body table td {
padding: 6px 13px;
border: 1px solid #dfe2e5;
}
.markdown-body table tr {
background-color: #fff;
border-top: 1px solid #c6cbd1;
}
.markdown-body table tr:nth-child(2n) {
background-color: #f6f8fa;
}
.markdown-body img {
max-width: 100%;
}
</style>
</head>
<body>
<div class="header">
<h1>Markdown实时预览工具</h1>
</div>
<div class="toolbar">
<div class="left-toolbar">
<button id="upload-btn">上传Markdown文件</button>
<input type="file" id="file-input" accept=".md,.markdown">
</div>
<div class="right-toolbar">
<button id="download-btn">下载HTML</button>
</div>
</div>
<div class="container">
<div class="editor-pane">
<textarea id="markdown-input" placeholder="在此输入Markdown文本..."># Markdown 实时预览工具
这是一个使用 **marked.js** 实现的Markdown实时预览工具。
## 功能特点
- 左右分栏布局
- 左侧编辑,右侧实时预览
- 预览效果与导出的HTML一致
- 支持常见的Markdown语法
### 代码示例
```javascript
function hello() {
console.log("Hello, Markdown!");
}
```
### 表格示例
```
| 语法 | 描述 |
|------|------|
| 标题 | 使用 `#` |
| 列表 | 使用 `-` 或 `*` |
| 链接 | `[text](url)` |
```
> 提示:尝试在左侧编辑内容,右侧会实时更新预览效果。</textarea>
</div>
<div class="preview-pane">
<div id="preview-content" class="preview-content markdown-body"></div>
</div>
</div>
<script>
// 获取DOM元素
const markdownInput = document.getElementById('markdown-input');
const previewContent = document.getElementById('preview-content');
const downloadBtn = document.getElementById('download-btn');
const uploadBtn = document.getElementById('upload-btn');
const fileInput = document.getElementById('file-input');
// 配置marked.js
marked.setOptions({
breaks: true,
gfm: true,
highlight: function(code, lang) {
// 这里可以添加代码高亮逻辑,如果需要可以使用highlight.js
return code;
}
});
// 初始渲染
updatePreview();
// 监听输入变化
markdownInput.addEventListener('input', updatePreview);
// 更新预览函数
function updatePreview() {
const markdownText = markdownInput.value;
previewContent.innerHTML = marked.parse(markdownText);
}
// 上传文件处理
uploadBtn.addEventListener('click', function() {
fileInput.click();
});
fileInput.addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
markdownInput.value = e.target.result;
updatePreview();
};
reader.readAsText(file);
});
// 下载HTML文件
downloadBtn.addEventListener('click', function() {
const markdownText = markdownInput.value;
const htmlContent = marked.parse(markdownText);
const htmlTemplate = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Markdown导出</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h1, h2, h3, h4, h5, h6 {
margin-top: 24px;
margin-bottom: 16px;
font-weight: 600;
line-height: 1.25;
}
h1 {
padding-bottom: 0.3em;
font-size: 2em;
border-bottom: 1px solid #eaecef;
}
h2 {
padding-bottom: 0.3em;
font-size: 1.5em;
border-bottom: 1px solid #eaecef;
}
p {
margin-top: 0;
margin-bottom: 16px;
}
a {
color: #0366d6;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
code {
font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
padding: 0.2em 0.4em;
margin: 0;
font-size: 85%;
background-color: rgba(27, 31, 35, 0.05);
border-radius: 3px;
}
pre {
background-color: #f6f8fa;
border-radius: 3px;
padding: 16px;
overflow: auto;
line-height: 1.45;
}
pre code {
padding: 0;
margin: 0;
background-color: transparent;
border-radius: 0;
}
blockquote {
padding: 0 1em;
color: #6a737d;
border-left: 0.25em solid #dfe2e5;
margin: 0 0 16px 0;
}
table {
border-collapse: collapse;
margin: 16px 0;
width: 100%;
}
table th, table td {
padding: 6px 13px;
border: 1px solid #dfe2e5;
}
table tr {
background-color: #fff;
border-top: 1px solid #c6cbd1;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
img {
max-width: 100%;
}
</style>
</head>
<body>
${htmlContent}
</body>
</html>`;
const blob = new Blob([htmlTemplate], { type: 'text/html' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'markdown-export.html';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
});
</script>
</body>
</html>