使用vitepress风格+markdownit渲染页面 可以实时修改预览

使用vitepress风格+markdownit渲染页面 可以实时修改预览

hejiashenghejiasheng
0 次阅读
markdown单页渲染
文章目录

代码如下:

html
<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问题迟早需要解决,但是目前还需要进一步改善。

效果图:

图片

评论区0

还没有评论,快来抢沙发吧~

登录 后可发表评论