Markdown在线编辑器第三版
<style>.mnBox { margin: 20px; left: calc(50% - 81px); transform: translateX(-50%); padding: 0 15px; width: clamp(600px, 90vw, 1400px); box-shadow: 1px 1px 6px gray; background: linear-gradient(45deg, beige, aliceblue, beige); z-index: 1000; position: relative; }
.mnBox * { box-sizing: border-box; }
.barDiv { display: flex; gap: 6px; justify-content: flex-start; align-items: center; height: 50px; }
.mainarea { display: flex; gap: 15px; width: 100%; height: 75vh; }
.barDiv span:hover { box-shadow: 1px 1px 2px gray; color: red; }
.barDiv span { height: 26px; min-width: 72px; padding: 0 10px; line-height: 26px; font-size: 14px; text-align: center; border-radius: 10px; background: none; border: none; cursor: pointer; display: inline-block; }
#menus { left: 10px; top: 10px; background: aliceblue; padding: 12px 8px; border-radius: 8px; box-shadow: 1px 1px 3px gray; display: none; z-index: 9; position: absolute; }
#txtEditor, #showDiv { width: 50%; height: 100%; padding: 18px; background: #fff; }
#showDiv { font-size: 16px; overflow: auto; position: relative; }
#showDiv:empty::before { content: '效果预览'; position: absolute; color: #aaa; }
#showDiv p { margin: 0 10px; }
#showDiv code, #showDiv pre { background: #afeeee; padding: 2px 4px; tab-size: 4; }
#showDiv pre { white-space: pre-wrap; word-wrap: break-word; }
#showDiv blockquote { border-left: 3px solid #f0f8ff; }
#showDiv table { border-collapse: collapse; white-space: pre-wrap; box-sizing: border-box; }
#showDiv th, #showDiv td { padding: 8px 10px; border: 1px solid #999; }
#txtEditor { font-size: 18px; resize: none; tab-size: 4; }
.grow2 { flex-grow: 2; pointer-events: none; }
.tMid { text-align: center; }
</style>
<h1 class="tMid">Markdown在线编辑器</h1>
<div class="mnBox">
<div class="barDiv">
<span id="showMenuBox">快捷键</span>
<div id="menus"></div>
</div>
<div class="mainarea">
<textarea id="txtEditor" placeholder="输入Markdown文本"></textarea>
<div id="showDiv"></div>
</div>
<div class="barDiv">
<span id="copyMDContent">复制Markdown</span>
<span id="copyHtml">复制HTML</span>
<span class="grow2"></span>
<span id="clearContent" class="floatRight">重置</span>
</div>
</div>
<script type="module">
import { marked } from 'https://638183.freep.cn/638183/web/mod/marked.js';
import { copy } from 'https://638183.freep.cn/638183/web/mod/copy.js';
import { formatHTML } from 'https://638183.freep.cn/638183/web/mod/formathtml.js';
let scheduled = false;
let lastValue = '';
// 快捷键数组
const shortcutKeys = [
['1', '一级标题'],
['2', '二级标题'],
['3', '三级标题'],
['4', '四级标题'],
['5', '五级标题'],
['6', '六级标题'],
['`', '代码'],
['7', '多行代码'],
['8', '斜体'],
['9', '粗体'],
['0', '粗斜体'],
['-', '删除线'],
['=', '块引用'],
['h', '分隔线'],
['l', '无序列表'],
['u', '下划线'],
['t', '表格'],
['a', '链接'],
['p', '图片']
];
// 输出的样式
const cssCode = `\<style>
#showDiv { font-size: 18px; }
#showDiv p { margin: 10px 0; }
#showDiv code, #showDiv pre { background: #afeeee; padding: 2px 4px; tab-size: 4; }
#showDiv pre { white-space: pre-wrap; word-wrap: break-word; }
#showDiv blockquote { border-left: 3px solid #f0f8ff; }
#showDiv table { border-collapse: collapse; white-space: pre-wrap; box-sizing: border-box; }
#showDiv th, #showDiv td { padding: 8px 10px; border: 1px solid #999; }
#showDiv tr:firstChild { text-align: center; }
\</style>\n\n`;
addshortcutMenu(shortcutKeys, menus);
showMenuBox.onmouseenter = () => menus.style.display = 'block';
menus.onmouseleave = () => menus.style.display = 'none';
txtEditor.oninput = () => {
const value = txtEditor.value;
if (!scheduled && value !== lastValue) {
scheduled = true;
requestAnimationFrame(() => {
showDiv.innerHTML = marked.parse(value);
lastValue = value;
scheduled = false;
});
}
};
txtEditor.addEventListener('keydown', (e) => {
const keys = shortcutKeys.map(key => key);
if ((e.altKey && keys.includes(e.key)) || e.key === 'Tab') {
e.preventDefault();
handleKeydown(e.target, e.altKey, e.key);
showDiv.innerHTML = marked.parse(txtEditor.value);
}
});
clearContent.onclick = () => txtEditor.value = showDiv.innerHTML = '';
copyMDContent.onclick = () => copy(txtEditor.value);
copyHtml.onclick = () => copy(cssCode + formatHTML(showDiv.outerHTML));
// 快捷键菜单(keys数组结构 : )
function addshortcutMenu(keys, target) {
const fm = document.createDocumentFragment();
keys.forEach(key => {
const span = document.createElement('span');
span.textContent = key + `(Alt + ${key})`;
span.onclick = () => {
handleKeydown(txtEditor, true, key);
menus.style.display = 'none';
showDiv.innerHTML = marked(txtEditor.value);
txtEditor.focus();
};
fm.appendChild(span);
const br = document.createElement('br');
fm.appendChild(br);
});
target.appendChild(fm);
}
// 语法输入
function handleKeydown(elm, alt, key) {
if (alt) {
switch(key) {
case '1': addTitle(elm, 1); break;
case '2': addTitle(elm, 2); break;
case '3': addTitle(elm, 3); break;
case '4': addTitle(elm, 4); break;
case '5': addTitle(elm, 5); break;
case '6': addTitle(elm, 6); break;
case '7': addInlineElm(elm, '\n```\n', '\n```\n'); break;
case '8': addInlineElm(elm, '*', '*'); break;
case '9': addInlineElm(elm, '**', '**'); break;
case '0': addInlineElm(elm, '***', '***'); break;
case '`': addInlineElm(elm, '`', '`'); break;
case '-': addInlineElm(elm, '~~', '~~'); break;
case '=': addInlineElm(elm, '>', ''); break;
case 'a': addMedia(elm, 0); break;
case 'p': addMedia(elm, 1); break;
case 't': addMedia(elm, 2); break;
case 'h': addHr(elm); break;
case 'l': addInlineElm(elm, '- ', ''); break;
case 'u': addInlineElm(elm, '<u>', '</u>'); break;
default: return;
}
} else {
if (key === 'Tab') {
elm.setRangeText(' ');
elm.selectionStart += 4;
}
}
}
// 标题语法
function addTitle(elm, num) {
const selectedText = window.getSelection().toString();
const lineStart = isLineStart(elm);
let begin = elm.selectionStart;
let title = selectedText.length > 0 ? selectedText.trim() : '标题' + num;
let insertStr = (lineStart ? '' : '\n') + '#'.repeat(num) + ' ' +title;
elm.setRangeText(insertStr);
begin += num;
elm.selectionStart = begin + (lineStart ? 1 : 2);
elm.selectionEnd =begin + title.length + (lineStart ? 1 : 2);
}
// 行内语法
function addInlineElm(elm, strStart, strEnd) {
const selectedText = window.getSelection().toString();
let begin = elm.selectionStart + strStart.length;
let insertStr = strStart + (selectedText.length > 0 ? selectedText.trim() : '文本') + strEnd;
elm.setRangeText(insertStr);
elm.selectionStart = begin;
elm.selectionEnd = begin + insertStr.length - strStart.length - strEnd.length;
}
// 分隔线语法
function addHr(elm) {
const hr = '\n---\n';
elm.setRangeText(hr);
elm.selectionStart += hr.length;
}
// 表格和媒体语法
function addMedia(elm, idx) {
const mediaAr = [
'[锚](地址 "说明")',
'\n\n',
`\n| 序号| 项目一 | 项目二 | 项目三 |\n| :---: | :--- | ---: | --- |\n| 1 | 内容 | 内容 | 内容 |\n\n`,
];
elm.setRangeText(mediaAr);
elm.selectionStart += mediaAr.length;
}
// 判断是否为行首
function isLineStart(textarea) {
const start = textarea.selectionStart;
const value = textarea.value;
const textBeforeSelection = value.substring(0, start);
const lastNewlineIndex = textBeforeSelection.lastIndexOf('\n');
return (lastNewlineIndex === -1 && start === 0) || (lastNewlineIndex + 1 === start);
}
</script> <style>
.showDiv { font-size: 18px; }
.showDiv p { margin: 10px 0; }
.showDiv code, .showDiv pre { background: #afeeee; padding: 2px 4px; tab-size: 4; }
.showDiv pre { white-space: pre-wrap; word-wrap: break-word; }
.showDiv blockquote { border-left: 3px solid #f0f8ff; }
.showDiv table { border-collapse: collapse; white-space: pre-wrap; box-sizing: border-box; }
.showDiv th, .showDiv td { padding: 8px 10px; border: 1px solid #999; }
.showDiv tr:firstChild { text-align: center; }
</style>
<div class="showDiv">
<h1>Markdown在线编辑器第二版简单说明</h1>
<h2>主要更新内容</h2>
<ul>
<li>界面细节调整</li>
<li>功能按钮增删</li>
<li>新增辅助快捷菜单和组合键语法输入</li>
</ul>
<h3>关于语法辅助输入</h3>
<ol>
<li>展开“快捷键”菜单,点击相应子项目;</li>
<li>直接使用快捷组合键(“快捷键”菜单有提示)</li>
</ol>
<blockquote>
<p>
【说明一】有序列表未加入菜单子项目、也不提供快捷输入方式,请使用直接输入的方法,语法格式为:阿拉伯数字.空格+内容【例】
<code>1. 项目一</code>
<br>
【说明二】表格预设四列,可用管道符号
<code>|</code>
添加更多的列,每一行的管道符号应当一致。辅助插入的表格源码中,第二行是定义单元格居中方式,略作分析便可理解其规则。
<br>
【说明三】快捷组合键的安排,为避免与系统功能键的冲突,使用了 alt 做引导键,即按
<code>alt + 预设键</code>
即可上屏对应语法的语句,使用时注意
<strong>确保编辑框获得焦点</strong>
,上屏的语句代码中预设文本(若有)应改为自己的内容。
</p>
</blockquote>
<h2>其它</h2>
<p>Markdown在线编辑器成熟的产品很多,我这个功能比较弱小,主要对标论坛简单HTML帖子制作。工具所生成的HTML代码没有第三方依赖,直接可用。</p>
<p>复制HTML源码附带的CSS代码应根据帖子实际内容增删、修改,例如,假设内容中并没有表格,为避免冗余,表格相关的CSS属性可以删掉,当然,留着也没事。</p>
</div> 过年了,黑黑还在出最新版本的Markdown在线编辑器,辛苦了。
努力学习,同时祝福黑黑过年好,新春快乐,万事如意{:4_187:} 红影 发表于 2026-2-16 09:25
过年了,黑黑还在出最新版本的Markdown在线编辑器,辛苦了。
努力学习,同时祝福黑黑过年好,新春快乐,万 ...
居家办公,没事玩玩 祝贺Markdown在线编辑器第三版闪亮登场{:4_199:}
界面更加美观,功能更加完善,使用更加便捷{:4_172:}
祝福马老师除夕快乐,新春快乐,马年大吉{:4_176:} 杨帆 发表于 2026-2-16 14:59
祝贺Markdown在线编辑器第三版闪亮登场
界面更加美观,功能更加完善,使用更加便捷
新年好 马黑黑 发表于 2026-2-16 13:03
居家办公,没事玩玩
居家办公,很流行的工作方式,真好{:4_187:} 红影 发表于 2026-2-18 14:06
居家办公,很流行的工作方式,真好
假期哦 马黑黑 发表于 2026-2-18 19:51
假期哦
过大年呢,放假是必须的{:4_204:} 红影 发表于 2026-2-18 20:16
过大年呢,放假是必须的
但是俺得靠产业养家糊口,俺的产业不能有假期 马黑黑 发表于 2026-2-18 20:18
但是俺得靠产业养家糊口,俺的产业不能有假期
你居家办公,有没有假期你可以自己决定呢{:4_204:} 红影 发表于 2026-2-18 20:43
你居家办公,有没有假期你可以自己决定呢
对,俺自己批自己的假 马黑黑 发表于 2026-2-18 20:46
对,俺自己批自己的假
这样多好,多自由啊。{:4_187:} 红影 发表于 2026-2-20 21:51
这样多好,多自由啊。
是的 马黑黑 发表于 2026-2-20 23:07
是的
这才叫自由职业呢,从事这样的职业也才是自由的人。 红影 发表于 2026-2-21 09:32
这才叫自由职业呢,从事这样的职业也才是自由的人。
也成自谋职业 马黑黑 发表于 2026-2-21 11:38
也成自谋职业
不管怎么说,也是个自由的人。 红影 发表于 2026-2-22 09:24
不管怎么说,也是个自由的人。
自由自在无拘无束 马黑黑 发表于 2026-2-22 13:02
自由自在无拘无束
真好,令人羡慕{:4_204:} 红影 发表于 2026-2-22 21:33
真好,令人羡慕
就是吃不饱穿不暖
页:
[1]
2