系列文章
- 基於.NetCore開發部落格專案 StarBlog - (1) 為什麼需要自己寫一個部落格?
- 基於.NetCore開發部落格專案 StarBlog - (2) 環境準備和建立專案
- 基於.NetCore開發部落格專案 StarBlog - (3) 模型設計
- 基於.NetCore開發部落格專案 StarBlog - (4) markdown部落格批量匯入
- 基於.NetCore開發部落格專案 StarBlog - (5) 開始搭建Web專案
- 基於.NetCore開發部落格專案 StarBlog - (6) 頁面開發之部落格文章列表
- 基於.NetCore開發部落格專案 StarBlog - (7) 頁面開發之文章詳情頁面
- ...
前言
前一篇部落格完成了文章列表的開發,現在要來寫文章詳情頁面了(這篇更新應該沒遲到吧,嘿嘿)。
部落格網站最重要的可以說就是文章詳情頁面了,使用者來看部落格最關心首先是內容,其次是閱讀體驗,所以這個文章詳情頁面的設計不能馬虎~
思路
文章正文是以markdown格式儲存的,要在網頁上展示的話,需要把markdown渲染成HTML才行。
那麼就有兩種思路:
- 一種是在後端渲染,使用C#把markdown轉換成HTML然後渲染成網頁
- 另一種是後端直接輸出markdown,使用一些開源的JS庫實現markdown渲染
一開始我是採用第一種的後端渲染方式,用到的C#庫是Markdig,不過深入使用之後發現有一些想要的功能實現起來比較麻煩,特別是這個庫幾乎沒有文件,要自定義一些功能全靠看原始碼+猜,最後只能放棄轉而使用第二種方式。
本文對兩種方式的實現都會介紹,著重介紹第二種前端渲染。
後端渲染
關於Markdig這個庫的我之前寫的部落格有詳細的介紹,這裡不再重複,有興趣的同學可以看看:C#解析Markdown文件,實現替換圖片連結操作
首先Nuget安裝Markdig
這個庫
一行程式碼就可以實現markdown轉HTML
Markdig.Markdown.ToHtml(markdownContent);
當然直接渲染出來的頁面是很簡陋的,沒有程式碼高亮、沒有引用塊、沒有列表樣式啥的,所以單純這樣肯定是不夠的。
Markdig作為C#目前唯一積極維護的Markdown庫,自然是考慮到了擴充套件性,它設計了擴充套件系統,本身內建了20多個擴充套件,還可以安裝其他人開發的擴充套件用來實現例如程式碼高亮的效果。
使用擴充套件也很簡單,加個pipeline
引數就行
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
var result = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);
Markdig本身不自帶程式碼高亮擴充套件,需要使用第三方元件,我測試了下面這兩個能用
- Markdig.Prism:前端渲染,但需要服務端元件配合
- Markdown.ColorCode:服務端渲染
前端渲染
本專案最終選了前端渲染的方案,前端生態有眾多的markdown元件,看了一圈之後我最終選了Editor.md
這個元件。
主要看中它可以比較方便的實現文章的TOC(目錄)功能,還有不錯的高亮效果。
使用起來很簡單
首先把markdown輸出到網頁裡
<div id="test-editormd-view" class="post-content">
<textarea id="append-test" style="display:none;">@Model.Content</textarea>
</div>
加了display:none
不顯示這個textarea
,給使用者看markdown程式碼沒用
引入edtor.md
的樣式檔案
<link rel="stylesheet" href="~/lib/editormd/css/editormd.preview.min.css">
引入editor.md
的js,你沒看錯,就是這麼多。靜態資源在之前的文章裡已經安裝好了,這裡不再重複。詳見:(5) 開始搭建Web專案
<script src="~/lib/editormd/examples/js/jquery.min.js"></script>
<script src="~/lib/editormd/lib/marked.min.js"></script>
<script src="~/lib/editormd/lib/prettify.min.js"></script>
<script src="~/lib/editormd/lib/raphael.min.js"></script>
<script src="~/lib/editormd/lib/underscore.min.js"></script>
<script src="~/lib/editormd/lib/sequence-diagram.min.js"></script>
<script src="~/lib/editormd/lib/flowchart.min.js"></script>
<script src="~/lib/editormd/lib/jquery.flowchart.min.js"></script>
<script src="~/lib/editormd/editormd.min.js"></script>
然後,使用js呼叫editor.md
的渲染方法
let testEditormdView = editormd.markdownToHTML("test-editormd-view", {
// htmlDecode: "style,script,iframe", // you can filter tags decode
htmlDecode: true,
//toc : false,
tocm: true, // Using [TOCM]
tocContainer: "#custom-toc-container", // 自定義 ToC 容器層
//gfm : false,
//tocDropdown : true,
// markdownSourceCode : true, // 是否保留 Markdown 原始碼,即是否刪除儲存原始碼的 Textarea 標籤
emoji: true,
taskList: true,
tex: true, // 預設不解析
flowChart: true, // 預設不解析
sequenceDiagram: true, // 預設不解析
})
搞定。
ViewModel
Post模型只是存在資料庫中的資料,直接展示不能完全滿足網頁設計的需求,所以還是一樣,需要定義一個ViewModel來用。
依然是放在StarBlog.Web/ViewModels
程式碼如下
public class PostViewModel {
public string Id { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public string Content { get; set; }
public string ContentHtml { get; set; }
public string Path { get; set; }
public DateTime CreationTime { get; set; }
public DateTime LastUpdateTime { get; set; }
public Category Category { get; set; }
public List<Category> Categories { get; set; }
}
相比起Post模型,多了ContentHtml
,Categories
改成列表
Service
關鍵的渲染部分介紹完了,講一下一些次要的~
Service的作用是把Post模型轉換成ViewModel
那直接上程式碼吧
public PostViewModel GetPostViewModel(Post post) {
var vm = new PostViewModel {
Id = post.Id,
Title = post.Title,
Summary = post.Summary,
Content = post.Content,
ContentHtml = Markdig.Markdown.ToHtml(post.Content),
Path = post.Path,
CreationTime = post.CreationTime,
LastUpdateTime = post.LastUpdateTime,
Category = post.Category,
Categories = new List<Category>()
};
foreach (var itemId in post.Categories.Split(",").Select(int.Parse)) {
var item = _categoryRepo.Where(a => a.Id == itemId).First();
if (item != null) vm.Categories.Add(item);
}
return vm;
}
雖然不用後端渲染方案,不過我還是保留了Markdig的後端渲染。
View
PS:Controller部分被我略過了,實在是太簡單,沒必要貼程式碼了
這個好像也沒啥好介紹的,那還是不貼完整程式碼了,詳細程式碼在這:https://github.com/Deali-Axy/StarBlog/blob/master/StarBlog.Web/Views/Blog/Post.cshtml
使用Bootstrap的Grid佈局做左右兩欄,左欄顯示文章的TOC目錄,右欄顯示文章的主體內容。
頁面頂部要展示分類的層級關係,不同分類之間用“/”分隔,但第一個分類前面不要有斜槓(複雜的表述方式)
這個需求的實現程式碼是這樣
<div>
分類:
@foreach (var category in Model.Categories) {
@if (Model.Categories.IndexOf(category) > 0) {
<span> / </span>
}
<a asp-controller="Blog" asp-action="List"
asp-route-categoryId="@category.Id">
@category.Name
</a>
}
</div>
效果大概這樣:
然後還要優化一下時間的顯示
@Model.LastUpdateTime.ToShortDateString()
@Model.LastUpdateTime.ToString("hh:mm")
完成之後的效果如下
實現效果
大概就是這樣,後續可能會再優化一下頁面。
搞定~