代码如下:
<div style="display:flex;gap:20px;height:100vh;"> <textarea id="editor" style="width:50%;padding:1rem;font-size:14px;"></textarea> <div id="preview" class="vp-doc" style="width:50%;overflow:auto;padding:1rem;"></div></div><script type="module">import MarkdownIt from "https://esm.sh/markdown-it@14";import mkContainer from "https://esm.sh/markdown-it-container";import mkTask from "https://esm.sh/markdown-it-task-lists";import mkAnchor from "https://esm.sh/markdown-it-anchor";import mkAttrs from "https://esm.sh/markdown-it-attrs";import { getHighlighter } from "https://esm.sh/shiki@1.22.0";// 系统主题const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");const getTheme = () => prefersDark.matches ? "vitesse-dark" : "vitesse-light";// Shiki 高亮const highlighter = await getHighlighter({ themes: ["vitesse-dark","vitesse-light"], langs: ["js","ts","bash","json","html","css","markdown","yaml"]});// 解析 ``` 后元信息,例如 {2,4-5} lnfunction parseMeta(meta=""){ const res = {highlight:[], lineNumbers:false}; const range = meta.match(/{([^}]+)}/); if(range){ const parts = range[1].split(","); for(const p of parts){ if(p.includes("-")){ const [a,b] = p.split("-").map(Number); for(let i=a;i<=b;i++) res.highlight.push(i); } else { const n=Number(p); if(!isNaN(n)) res.highlight.push(n); } } } if(/\b(ln|line-numbers)\b/i.test(meta)) res.lineNumbers = true; return res;}// 将 [!NOTE]、[!TIP] 等行首标记转成 div.custom-blockfunction markdownCustomBlock(md){ const map = { NOTE: "tip", TIP: "tip", IMPORTANT: "important", WARNING: "warning", CAUTION: "caution" }; md.core.ruler.push("custom_block", state => { const tokens = state.tokens; for(let i=0;i<tokens.length;i++){ if(tokens[i].type==="paragraph_open"){ const contentToken = tokens[i+1]; if(contentToken && contentToken.type==="inline"){ const match = contentToken.content.match(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*(.*)/); if(match){ const type = map[match[1]]; const text = match[2]; tokens[i].type = "html_block"; tokens[i].content = `<div class="custom-block ${type}">`; contentToken.type = "html_block"; contentToken.content = text; const closeToken = tokens[i+2]; if(closeToken && closeToken.type==="paragraph_close") closeToken.type="html_block", closeToken.content="</div>"; } } } } });}const md = new MarkdownIt({ html:true, linkify:true, typographer:true, highlight:(code,lang,meta)=>{ const {highlight,lineNumbers}=parseMeta(meta); const lineOptions = highlight.map(line=>({line,classes:["highlighted"]})); try{ let html = highlighter.codeToHtml(code,{lang:lang||"text",theme:getTheme(),lineOptions}); if(lineNumbers) html = html.replace('<pre class="shiki"','<pre class="shiki has-line-numbers"'); return html; }catch{ return `<pre><code>${md.utils.escapeHtml(code)}</code></pre>`; } }}).use(mkTask,{enabled:true}).use(mkAttrs).use(mkAnchor,{permalink:mkAnchor.permalink.ariaHidden({})}).use(markdownCustomBlock);// 可选 :::tip / :::warning 容器md.use(mkContainer,"tip",{render:(tokens,idx)=>tokens[idx].nesting===1?'<div class="custom-block tip">':'</div>'});md.use(mkContainer,"warning",{render:(tokens,idx)=>tokens[idx].nesting===1?'<div class="custom-block warning">':'</div>'});const editor=document.getElementById("editor");const preview=document.getElementById("preview");function render(){ preview.innerHTML = md.render(editor.value); }prefersDark.addEventListener("change", render);editor.addEventListener("input", render);editor.value=`# VitePress 风格 + Shiki 高亮 Demo[!NOTE] 强调用户在快速浏览文档时也不应忽略的重要信息[!TIP] 有助于用户顺利达成目标的建议性信息[!IMPORTANT] 对用户达成目标至关重要的信息[!WARNING] 存在风险,需要立即关注的内容[!CAUTION] 行为可能带来的负面影响:::tip这是一个 tip 容器::::::warning这是一个 warning 容器:::- [ ] 待办- [x] 已完成## 代码示例(行高亮 + 行号)\`\`\`js {2,4} lnfunction greet(name) { console.log("Hello,", name);}greet("Shiki");\`\`\`## YAML 示例\`\`\`yamltitle: helloitems: - a - b\`\`\``;render();</script><!-- VitePress CSS --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/vars.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/base.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/fonts.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/icons.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/utils.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/components/custom-block.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/components/vp-code.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/components/vp-doc.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vitepress@1.6.4/dist/client/theme-default/styles/components/vp-table.css"><!-- 优化配色:代码块 + custom-block --><style>/* 代码块 */.vp-doc pre.shiki{ border-radius:12px; overflow:auto; padding:1rem; font-size:14px; line-height:1.5; margin:1em 0; box-shadow:0 2px 6px rgba(0,0,0,0.05); background-color: #f5f5f5 !important; /* 浅灰背景 */ color: #1e1e2e !important;}@media (prefers-color-scheme: dark){ .vp-doc pre.shiki{ background-color:#2e2e3e; color:#f0f0f0; }}.vp-doc pre.shiki code{ counter-reset:line; }.vp-doc pre.shiki .line{ display:block; min-height:1.25rem; counter-increment:line; padding-left:0.5em;}.vp-doc pre.shiki.has-line-numbers .line::before{ content:counter(line); display:inline-block; width:2.5em; margin-right:1em; text-align:right; opacity:.5; user-select:none;}.vp-doc pre.shiki .line.highlighted{ background: rgba(255,245,157,0.2); margin:0 calc(-1rem); padding:0 1rem;}/* custom-block 背景色 */.custom-block.tip{ background-color:#e0f7ff; color:#055160; }.custom-block.warning{ background-color:#fff4e5; color:#663c00; }.custom-block.important{ background-color:#fff0f0; color:#660000; }.custom-block.caution{ background-color:#fff8e0; color:#665500; }/* 深色模式 custom-block */@media (prefers-color-scheme: dark){ .custom-block.tip{ background-color:#004c66; color:#b0eaff; } .custom-block.warning{ background-color:#664400; color:#ffe5b0; } .custom-block.important{ background-color:#660000; color:#ffb0b0; } .custom-block.caution{ background-color:#665500; color:#fff4b0; }}</style>渲染单页和页面css问题迟早需要解决,但是目前还需要进一步改善。
效果图:

