2
头图

什么是markdown

Markdown 是一种轻量级标记语言,创始人为约翰·格鲁伯(John Gruber)。 它允许人们使用易读易写的纯文本格式编写文档,然后转换成有效的 XHTML(或者HTML)文档。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。

由于 Markdown 的轻量化、易读易写特性,并且对于图片,图表、数学式都有支持,许多网站都广泛使用 Markdown 来撰写帮助文档或是用于论坛上发表消息。 如 GitHubRedditDiasporaStack ExchangeOpenStreetMapSourceForge、简书等,甚至还能被使用来撰写电子书。现在我们所看的 segmentfault 的编辑器也是支持markdown语法的!

上代码

</!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta charset="utf-8">
    <script src="https://cdn.staticfile.org/jquery/3.6.1/jquery.min.js"></script>
    <style>
        *{
            padding: 0;
            margin: 0;
            font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
        }
        #app{
            width: 1610px;
            height: 800px;
            margin: 30px auto 0;
            padding: 10px 10px;
            background: #eee;
        }
        #app .md-editor{
            width: 800px;
            height: 800px;
            float: left;
        }
        #app .md-content{
            width: 100%;
            height: 800px;
            outline: none;
            resize: none;
            padding: 10px 10px;
            font-size: 16px;
            border: none;
            background: #fff;
            color: #666;
        }
        #app .md-html{
            width: 780px;
            height: 780px;
            float: right;
            background: #fff;
            padding: 10px 10px;
            line-height: 20px;
        }
        #app .md-html .placeholder{
            font-size: 16px;
            color: #666;
        }
        #app code{
            color: #666;
            padding: 3px 5px;
            background: #f1f1f1;
            border-radius: 2px;
            font-size: 12px;
        }

        #app pre{
            /*width: 100%;*/
            /*display: block;*/
            color: #666;
            padding: 10px 10px;
            background: #f1f1f1;
            border-radius: 5px;
            font-size: 14px;
        }

        h1, h2, h3, h4, h5, h6{
          font-weight: 600;
          line-height: 1.25;
          margin-bottom: 0;
        }
        h1, h2{
          border-bottom: 1px solid #eaecef;
          padding-bottom: 12px;
        }
    </style>
</head>
<body>

<h2 style="text-align: center;margin-top: 50px;">JavaScript实现一个简单的Markdown语法解析器</h2>
<div id="app">
    
    <div class="md-editor">
        <form>
            <textarea name="md-content" class="md-content" placeholder="在这里使用markdown语法编写"></textarea>
        </form>
    </div>
    <div class="md-html"><span class="placeholder">这里会实时显示markdown语法的解析结果</span></div>
</div>

<script type="text/javascript">

// 解析markdown语法为html
function markdownToHTML(markdown) {
  
  // 将Markdown文本分成多行
  const lines = markdown.split('\n');

  // 用于保存解析后的HTML代码
  let result = '';

  // 遍历每一行Markdown文本
  for (let i = 0; i < lines.length; i++) {

    const line = lines[i];
    
    // 处理标题
    if (line.startsWith('#')) {
      const level = line.match(/^#+/)[0].length;
      const title = line.substring(level).trim();
      result += `<h${level}>${title}</h${level}>`;
    }

    // 处理无序列表
    else if (line.startsWith('* ')) {
      const text = line.substring(2).trim();
      result += `<li>${text}</li>`;
    }

    // 处理有序列表
    else if (/^\d+\.\s/.test(line)) {
      const text = line.substring(line.indexOf('.') + 1).trim();
      result += `<li>${text}</li>`;
    }

    // 处理加粗
    else if (line.startsWith('**')) {
      result += line.replace(/\*\*(.*)\*\*/gm, '<strong>$1</strong>');
    }
    else if (line.startsWith('__')) {
      result += line.replace(/__(.*)__/gm, '<strong>$1</strong>');
    }

    // 处理斜体
    else if (line.startsWith('*')) {
      result += line.replace(/\*(.*)\*/gm, '<em>$1</em>');
    }
    else if (line.startsWith('_')) {
      result += line.replace(/_(.*)_/gm, '<em>$1</em>');
    }

    // 处理删除线
    else if (line.startsWith('~~')) {
      result += line.replace(/~~(.*)~~/gm, '<del>$1</del>');
    }

    // 处理超链接
    else if (line.startsWith('[')) {
      result += line.replace(/\[(.*?)\]\((.*?)\)/gm, '<a href="$2">$1</a>');
    }

    // 处理图片
    else if (line.startsWith('![')) {
      result += line.replace(/!\[(.*?)\]\((.*?)\)/gm, '<img src="$2" alt="$1" width="200" />');
    }
    
    // 处理行内代码
    else if (line.startsWith('`')) {
      result += escapeHtml(line).replace(/`(.*?)`/gm, '<code>$1</code>');
    }

    // 处理段落
    else {
      if(line.length == 0){
        result += `<br/>`;
      }else{
        result += `<p>${line}</p>`;
      }
    }

  }

  // 包装HTML代码
  result = `<div>${result}</div>`;
  return result;
}

// html转义
function escapeHtml(str) {
  return str.replace(/[&<>"']/g, function(match) {
    switch(match) {
      case '&':
        return '&amp;';
      case '<':
        return '&lt;';
      case '>':
        return '&gt;';
      case '"':
        return '&quot;';
      case '\'':
        return '&#39;';
    }
  });
}

// 实时解析markdown语法
$("#app .md-editor .md-content").bind("input propertychange",function(event){

    let md_content = $('#app .md-editor .md-content').val();

    if(md_content){

      $('#app .md-html').html(markdownToHTML(md_content));
    }else{

      $('#app .md-html').html('<span class="placeholder">这里会实时显示markdown语法的解析结果</span>');
    }
    
});


</script>
</body>
</html>

实现原理

实现起来非常简单,就是通过正则替换预定的字符来实现HTML的输出。

demo

image.png

作者

TANKING


TANKING
4.8k 声望493 粉丝

热爱分享,热爱创作,热爱研究。