天天看點

基于.NetCore開發部落格項目 StarBlog - (7) 頁面開發之文章詳情頁面

系列文章

  • 基于.NetCore開發部落格項目 StarBlog - (1) 為什麼需要自己寫一個部落格?
  • 基于.NetCore開發部落格項目 StarBlog - (2) 環境準備和建立項目
  • 基于.NetCore開發部落格項目 StarBlog - (3) 模型設計
  • 基于.NetCore開發部落格項目 StarBlog - (4) markdown部落格批量導入
  • 基于.NetCore開發部落格項目 StarBlog - (5) 開始搭建Web項目
  • 基于.NetCore開發部落格項目 StarBlog - (6) 頁面開發之部落格文章清單
  • 基于.NetCore開發部落格項目 StarBlog - (7) 頁面開發之文章詳情頁面
  • 基于.NetCore開發部落格項目 StarBlog - (8) 分類層級結構展示
  • 基于.NetCore開發部落格項目 StarBlog - (9) 圖檔批量導入
  • 基于.NetCore開發部落格項目 StarBlog - (10) 圖檔瀑布流
  • 基于.NetCore開發部落格項目 StarBlog - (11) 實作通路統計
  • 基于.NetCore開發部落格項目 StarBlog - (12) Razor頁面動态編譯
  • 基于.NetCore開發部落格項目 StarBlog - (13) 加入友情連結功能
  • 基于.NetCore開發部落格項目 StarBlog - (14) 實作主題切換功能
  • 基于.NetCore開發部落格項目 StarBlog - (15) 生成随機尺寸圖檔
  • ...

前言

前一篇部落格完成了文章清單的開發,現在要來寫文章詳情頁面了(這篇更新應該沒遲到吧,嘿嘿)。

部落格網站最重要的可以說就是文章詳情頁面了,使用者來看部落格最關心首先是内容,其次是閱讀體驗,是以這個文章詳情頁面的設計不能馬虎~

思路

文章正文是以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>
           

效果大概這樣:

基于.NetCore開發部落格項目 StarBlog - (7) 頁面開發之文章詳情頁面

然後還要優化一下時間的顯示

@Model.LastUpdateTime.ToShortDateString()
@Model.LastUpdateTime.ToString("hh:mm")
           

完成之後的效果如下

實作效果

基于.NetCore開發部落格項目 StarBlog - (7) 頁面開發之文章詳情頁面

大概就是這樣,後續可能會再優化一下頁面。

搞定~

微信公衆号:「程式設計實驗室」

專注于網際網路熱門新技術探索與團隊靈活開發實踐,包括架構設計、機器學習與資料分析算法、移動端開發、Linux、Web前後端開發等,歡迎一起探讨技術,分享學習實踐經驗。

繼續閱讀