系列文章
基于.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?decodehtmlDecode:?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")
完成之后的效果如下
實現效果

大概就是這樣,后續可能會再優化一下頁面。
搞定~