• 基于.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本身不自带代码高亮扩展,需要使用第三方组件,我测试了下面这两个能用

    前端渲染

    本项目最终选了前端渲染的方案,前端生态有众多的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模型,多了ContentHtmlCategories改成列表

    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>
    

    效果大概这样:

    image

    然后还要优化一下时间的显示

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

    完成之后的效果如下

    实现效果

    image

    大概就是这样,后续可能会再优化一下页面。

    搞定~


    __EOF__

  • 本文作者: 程序设计实验室
  • 本文链接: https://www.cnblogs.com/deali/p/16293309.html
  • 关于博主: 公众号:程序设计实验室,欢迎交流~
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    机器学习-神经网络
    Java final关键字的简介说明
    CSS常用技巧
    图像处理之图像质量评价指标MSE(均方误差)
    linux系统编程
    Python编程 列表的操作(2)
    如何设置CentOS系统以禁用不必要的网络端口和服务?
    “混合”引擎为通用子模块提供动力,实现嵌入式I / O灵活性
    基于Java+SpringBoot+vue前后端分离小徐影城管理系统设计实现
    【Linux-ARM】安装 RabbitMQ
  • 原文地址:https://www.cnblogs.com/deali/p/16293309.html