基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (7) 頁(yè)面開(kāi)發(fā)之文章詳情頁(yè)面
系列文章
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (1) 為什么需要自己寫(xiě)一個(gè)博客?
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (2) 環(huán)境準(zhǔn)備和創(chuàng)建項(xiàng)目
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (3) 模型設(shè)計(jì)
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (4) markdown博客批量導(dǎo)入
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (5) 開(kāi)始搭建Web項(xiàng)目
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (6) 頁(yè)面開(kāi)發(fā)之博客文章列表
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (7) 頁(yè)面開(kāi)發(fā)之文章詳情頁(yè)面
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (8) 分類(lèi)層級(jí)結(jié)構(gòu)展示
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (9) 圖片批量導(dǎo)入
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (10) 圖片瀑布流
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (11) 實(shí)現(xiàn)訪(fǎng)問(wèn)統(tǒng)計(jì)
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (12) Razor頁(yè)面動(dòng)態(tài)編譯
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (13) 加入友情鏈接功能
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (14) 實(shí)現(xiàn)主題切換功能
- 基于.NetCore開(kāi)發(fā)博客項(xiàng)目 StarBlog - (15) 生成隨機(jī)尺寸圖片
- ...
前言
前一篇博客完成了文章列表的開(kāi)發(fā),現(xiàn)在要來(lái)寫(xiě)文章詳情頁(yè)面了(這篇更新應(yīng)該沒(méi)遲到吧,嘿嘿)。
博客網(wǎng)站最重要的可以說(shuō)就是文章詳情頁(yè)面了,用戶(hù)來(lái)看博客最關(guān)心首先是內(nèi)容,其次是閱讀體驗(yàn),所以這個(gè)文章詳情頁(yè)面的設(shè)計(jì)不能馬虎~
思路
文章正文是以markdown格式存儲(chǔ)的,要在網(wǎng)頁(yè)上展示的話(huà),需要把markdown渲染成HTML才行。
那么就有兩種思路:
- 一種是在后端渲染,使用C#把markdown轉(zhuǎn)換成HTML然后渲染成網(wǎng)頁(yè)
- 另一種是后端直接輸出markdown,使用一些開(kāi)源的JS庫(kù)實(shí)現(xiàn)markdown渲染
一開(kāi)始我是采用第一種的后端渲染方式,用到的C#庫(kù)是Markdig,不過(guò)深入使用之后發(fā)現(xiàn)有一些想要的功能實(shí)現(xiàn)起來(lái)比較麻煩,特別是這個(gè)庫(kù)幾乎沒(méi)有文檔,要自定義一些功能全靠看源碼+猜,最后只能放棄轉(zhuǎn)而使用第二種方式。
本文對(duì)兩種方式的實(shí)現(xiàn)都會(huì)介紹,著重介紹第二種前端渲染。
后端渲染
關(guān)于Markdig這個(gè)庫(kù)的我之前寫(xiě)的博客有詳細(xì)的介紹,這里不再重復(fù),有興趣的同學(xué)可以看看:C#解析Markdown文檔,實(shí)現(xiàn)替換圖片鏈接操作
首先Nuget安裝Markdig這個(gè)庫(kù)
一行代碼就可以實(shí)現(xiàn)markdown轉(zhuǎn)HTML
Markdig.Markdown.ToHtml(markdownContent);
當(dāng)然直接渲染出來(lái)的頁(yè)面是很簡(jiǎn)陋的,沒(méi)有代碼高亮、沒(méi)有引用塊、沒(méi)有列表樣式啥的,所以單純這樣肯定是不夠的。
Markdig作為C#目前唯一積極維護(hù)的Markdown庫(kù),自然是考慮到了擴(kuò)展性,它設(shè)計(jì)了擴(kuò)展系統(tǒng),本身內(nèi)置了20多個(gè)擴(kuò)展,還可以安裝其他人開(kāi)發(fā)的擴(kuò)展用來(lái)實(shí)現(xiàn)例如代碼高亮的效果。
使用擴(kuò)展也很簡(jiǎn)單,加個(gè)pipeline參數(shù)就行
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
var result = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);
Markdig本身不自帶代碼高亮擴(kuò)展,需要使用第三方組件,我測(cè)試了下面這兩個(gè)能用
- Markdig.Prism:前端渲染,但需要服務(wù)端組件配合
- Markdown.ColorCode:服務(wù)端渲染
前端渲染
本項(xiàng)目最終選了前端渲染的方案,前端生態(tài)有眾多的markdown組件,看了一圈之后我最終選了Editor.md這個(gè)組件。
主要看中它可以比較方便的實(shí)現(xiàn)文章的TOC(目錄)功能,還有不錯(cuò)的高亮效果。
使用起來(lái)很簡(jiǎn)單
首先把markdown輸出到網(wǎng)頁(yè)里
<div id="test-editormd-view" class="post-content">
<textarea id="append-test" style="display:none;">@Model.Content</textarea>
</div>
加了display:none不顯示這個(gè)textarea,給用戶(hù)看markdown代碼沒(méi)用
引入edtor.md的樣式文件
<link rel="stylesheet" href="~/lib/editormd/css/editormd.preview.min.css">
引入editor.md的js,你沒(méi)看錯(cuò),就是這么多。靜態(tài)資源在之前的文章里已經(jīng)安裝好了,這里不再重復(fù)。詳見(jiàn):(5) 開(kāi)始搭建Web項(xiàng)目
<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調(diào)用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 標(biāo)簽
emoji: true,
taskList: true,
tex: true, // 默認(rèn)不解析
flowChart: true, // 默認(rèn)不解析
sequenceDiagram: true, // 默認(rèn)不解析
})
搞定。
ViewModel
Post模型只是存在數(shù)據(jù)庫(kù)中的數(shù)據(jù),直接展示不能完全滿(mǎn)足網(wǎng)頁(yè)設(shè)計(jì)的需求,所以還是一樣,需要定義一個(gè)ViewModel來(lái)用。
依然是放在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
關(guān)鍵的渲染部分介紹完了,講一下一些次要的~
Service的作用是把Post模型轉(zhuǎn)換成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;
}
雖然不用后端渲染方案,不過(guò)我還是保留了Markdig的后端渲染。
View
PS:Controller部分被我略過(guò)了,實(shí)在是太簡(jiǎn)單,沒(méi)必要貼代碼了
這個(gè)好像也沒(méi)啥好介紹的,那還是不貼完整代碼了,詳細(xì)代碼在這:https://github.com/Deali-Axy/StarBlog/blob/master/StarBlog.Web/Views/Blog/Post.cshtml
使用Bootstrap的Grid布局做左右兩欄,左欄顯示文章的TOC目錄,右欄顯示文章的主體內(nèi)容。
頁(yè)面頂部要展示分類(lèi)的層級(jí)關(guān)系,不同分類(lèi)之間用“/”分隔,但第一個(gè)分類(lèi)前面不要有斜杠(復(fù)雜的表述方式)
這個(gè)需求的實(shí)現(xiàn)代碼是這樣
<div>
分類(lèi):
@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>
效果大概這樣:

然后還要優(yōu)化一下時(shí)間的顯示
@Model.LastUpdateTime.ToShortDateString()
@Model.LastUpdateTime.ToString("hh:mm")
完成之后的效果如下
實(shí)現(xiàn)效果

大概就是這樣,后續(xù)可能會(huì)再優(yōu)化一下頁(yè)面。
搞定~

浙公網(wǎng)安備 33010602011771號(hào)