基於.NetCore開發部落格項目 StarBlog – (19) Markdown渲染方案探索

前言

筆者認為,一個部落格網站,最核心的是閱讀體驗。

在開發StarBlog的過程中,最耗時的恰恰也是文章的展示部分功能。

最開始還沒研究出來如何很好的使用後端渲染,所以只能先用Editor.md組件做前端渲染,過渡一下。前端渲染我是不滿意的,因為性能較差,頁面載入出來還會閃一下,有割裂感,影響體驗。

現在我已經做出了比較完善的後端渲染方案,前端渲染就可以直接退休了。本文介紹StarBlog部落格開發過程中的各種Markdown渲染方案(主要是介紹後端渲染)。

兩種方案

前端渲染

使用 Editor.md 組件進行渲染,效果差強人意,主要是看中了其可以生成 ToC(文章目錄) 的功能,但生成的 ToC 效果也比較差,後面是我fork了一份源碼進行魔改才好一點。

魔改過程在這篇文章:魔改editormd組件,優化ToC渲染效果

優化 ToC 的這個功能我給官方提了PR,但沒有響應,看了一下GitHub里有幾十個PR,上次提交也是快4年前的事了,看來這個項目真的涼了……

除了這個 editor.md ,還有其他幾個前端的方案:

看起來都不錯,有沒有 ToC 我沒研究,部落格園上有大佬寫了一篇比較的文章,有興趣的同學可以在參考資料中看看~

後端渲染

目前 C# 可用的 Markdown 庫似乎只有 Markdig ,一開始我還在吐槽文檔缺失導致很難用,甚至一度想自己造輪子重新做一個,不過最近有所改善,在研究了官方新增的幾個文檔之後,我對這個庫的了解又加深了一些,功能確實很多,設計得也不錯,擴展性很好~

所以暫時就用這個啦~

目前我的做法是用 Markdig 將 Markdown 生成 HTML,然後前端展示這個 HTML ,再結合 Bootstrap 或者 github-markdown-css 等樣式庫來美化正文顯示效果,用 highlight.js 之類的JS庫實現程式碼高亮。

至於文章的 ToC ,Markdig 沒有現成的,我自己造輪子實現~

詳見這篇文章:C#實現生成Markdown文檔目錄樹

其實算是一種混合式的方案吧~

接下來介紹的內容圍繞後端渲染展開。

處理 ToC

上一篇文章對於生成目錄樹已經說得比較清楚了,本文不再重複那麼多,只說一下有區別的地方~

先解析Markdown文檔,拿到所有標題節點

var headings = new List<Heading>();

foreach (var heading in document.Descendants<HeadingBlock>()) {
  var item = new Heading {Level = heading.Level, Text = heading.Inline?.FirstChild?.ToString()};
  headings.Add(item);
}

遍歷進行處理。

原本直接把標題作為錨點的 href 屬性,實際使用的時候是不行的,根據測試,Markdig生成錨點ID的規則如下

中文按照

  • section
  • section-1
  • section-2

section後面的數字是在所有中文標題里出現的順序,不是在全部標題裡面的順序。

英文就替換空格 + 轉小寫 (未考慮其他情況,事實上應該把特殊符號也一併替換掉)

所以處理 href 的時候分兩種情況,用正則表達式 [\u4e00-\u9fbb] 檢測是否包含中文字元。

var chineseTitleCount = 0;
for (var i = 0; i < headings.Count; i++) {
  var item = headings[i];
  var text = item.Text ?? "";
  if (Regex.IsMatch(text, "[\u4e00-\u9fbb]")) {
    item.Slug = chineseTitleCount == 0 ? "section" : $"section-{chineseTitleCount}";
    chineseTitleCount++;
  }
  else {
    item.Slug = text.Replace(" ", "-").ToLower();
  }
  // ...
}

搞定

樣式

bootstrap 默認樣式

默認樣式還可以,不過會覺得少了點啥,或許可以研究一下各種在線Markdown編輯器的樣式~

github-markdown-css

顧名思義是GitHub的markdown樣式

地址: //www.npmjs.com/package/github-markdown-css

安裝後有三個文件

  • github-markdown.css: (默認) 通過 @media (prefers-color-scheme) 實現自動切換亮色/暗色主題
  • github-markdown-light.css: 亮色主題
  • github-markdown-dark.css: 暗色主題

官網還有一句話,但我不知道怎麼自己生成,難道要我去github扒css下來?

You may know that now GitHub supports more than 2 themes including dark_dimmed, dark_high_contrast and colorblind variants. If you want to try these themes, you can generate them on your own!

安裝

yarn add github-markdown-css

引入

<link rel="stylesheet" href="~/lib/github-markdown-css/github-markdown-light.css">

使用

<div class="markdown-body">
  @Html.Raw(Model.ContentHtml)
</div>

效果

確實有GitHub內味了,但還沒程式碼高亮

image-20221026225955639

程式碼高亮

目前使用 highlight.js 包,官網: //www.npmjs.com/package/highlight.js

有很多其他的工具,不展開了,用這個足夠了~

下載

要在網頁上直接用沒辦法通過安裝NPM包的方式,只能通過網址下載: //highlightjs.org/download/

如果不想下載的話可以用CDN,但就只能支援部分語言高亮。

裡面有好多種語言,竟然沒全選按鈕,一個個選太麻煩了,我寫了個全選腳本,複製到瀏覽器控制台執行就能全選,然後下載。

document.querySelectorAll('input').forEach( item => {
    if(item.getAttribute('type')==='checkbox') item.checked=true
})

引入

下載後把zip解壓放到 wwwroot/lib

<link rel="stylesheet" href="~/lib/highlight/styles/default.min.css">
<script src="~/lib/highlight/highlight.min.js"></script>
<script>hljs.highlightAll();</script>

或者不下載,直接使用 CDN

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>

效果

有了程式碼高亮,一下就不一樣了

image-20221026235224582

還有很多其他主題,styles 目錄下很多,引入css的時候自行選擇即可

我來換個深色的主題看看

image-20221026235552813

系列文章

參考資料