要写文档了,emmm,先写个文档工具吧——DocMarkdown( 二 )

/grpc/ 。当以/结尾或为空值时,自动添加index 。然后得到路径/grpc/index
如果存在多语言,则于路径末尾添加.{lang} , {lang}为当前语言值 。最后于末尾添加.md扩展名 。得到路径/grpc/index.zh-cn.md
如果存在路径地址,则于路径前添加/{path}路径地址 。得到路径/docs/grpc/index.zh-cn.md
如果存在多版本 , 则于路径前添加/{version}{version}版本路径 。得到路径/main/docs/grpc/index.zh-cn.md
最后于路径前添加{baseUrl}基础地址 。得到路径https://raw.githubusercontent.com/who/project/main/docs/grpc/index.zh-cn.md
DocMarkdown将请求该地址以获取Markdown文档内容并解析生成Html内容展现出来 。
解析与渲染markdig能解析Markdown内容并返回一系列不同类型的对象,根据这些对象的类型,我们可以生成想要的内容对应的Razor组件
定义一个MarkdownRenderer用于解析对应类型的对象
public abstract class MarkdownRenderer{public abstract bool CanRender(MarkdownObject markdown);public abstract object Render(IMarkdownRenderContext context, MarkdownObject markdown);}public abstract class MarkdownRenderer<T> : MarkdownRendererwhere T : MarkdownObject{public override bool CanRender(MarkdownObject markdown){return markdown is T;}public override object Render(IMarkdownRenderContext context, MarkdownObject markdown){return Render(context, (T)markdown);}protected abstract object Render(IMarkdownRenderContext context, T markdown);}为什么返回object类型?这是由于Markdown里支持HTML内容,而markdig返回行内HTML内容时,会将一个元素拆成两个IarkdownRender 。一个是开头,例如<span>,一个是结尾,例如</span>
渲染Block和Inline
public RenderFragment RenderBlock(ContainerBlock containerBlock){return new RenderFragment(builder =>{int i = 0;foreach (var block in containerBlock){var obj = Render(block);if (obj is RenderFragment fragment)builder.AddContent(i, fragment);else if (obj is MarkupString markup)builder.AddContent(i, markup);else if (obj is HtmlElement html){if (html.IsEnd)builder.CloseComponent();else{builder.OpenElement(i, html.Tag);i++;if (html.Attributes != null){foreach (var attr in html.Attributes){if (attr.Value =https://www.huyubaike.com/biancheng/= null)builder.AddAttribute(i, attr.Key);elsebuilder.AddAttribute(i, attr.Key, attr.Value);i++;}}if (html.IsSelfClose)builder.CloseElement();}}elsebuilder.AddContent(i, obj);i++;}});}public RenderFragment RenderInline(ContainerInline containerInline){return new RenderFragment(content =>{var inline = containerInline.FirstChild;int i = 0;while (inline != null){var obj = Render(inline);if (obj is RenderFragment fragment)content.AddContent(i, fragment);else if (obj is MarkupString markup)content.AddContent(i, markup);else if (obj is HtmlElement html){if (html.IsEnd)content.CloseComponent();else{content.OpenElement(i, html.Tag);i++;if (html.Attributes != null){foreach (var attr in html.Attributes){if (attr.Value == null)content.AddAttribute(i, attr.Key);elsecontent.AddAttribute(i, attr.Key, attr.Value);i++;}}if (html.IsSelfClose)content.CloseElement();}}elsecontent.AddContent(i, obj);inline = inline.NextSibling;i++;}});}渲染整个Markdown文档
private void RenderMarkdown(RenderHandle renderHandle, MarkdownDocument document){var content = RenderBlock(document);renderHandle.Render(builder =>{builder.OpenComponent<LayoutView>(0);builder.AddAttribute(1, nameof(LayoutView.Layout), typeof(MainLayout));builder.AddAttribute(2, nameof(LayoutView.ChildContent), (RenderFragment)(child =>{child.OpenComponent<Index>(0);child.AddAttribute(1, "Content", content);child.CloseComponent();}));builder.CloseComponent();});}加载为了加快加载速度,按照官方文档,改为加载Brotli压缩后的文件并增加加载进度动画
<div id="app"><div class="position-fixed" style="bottom: 0; top: 0; left: 0; right: 0;"><div class="d-flex flex-column justify-content-center align-items-center h-100"><div style="width: 64px; height: 64px;"><svg viewBox="0 0 21 24"><path fill="transparent" d="M4.5,19.5A1.5,1.5,0,0,0,6,21H18.08V18H6A1.51,1.51,0,0,0,4.5,19.5Z" transform="translate(-1.5)" /><path fill="#1296db" d="M21.39,18a1.12,1.12,0,0,0,1.12-1.12V1.13A1.13,1.13,0,0,0,21.38,0H6A4.5,4.5,0,0,0,1.5,4.5v15A4.5,4.5,0,0,0,6,24H21.38a1.13,1.13,0,0,0,1.13-1.13v-.76A1.12,1.12,0,0,0,21.39,21h-.3V18Zm-4.14-4.54-2.93-4h1.79V5h2.3V9.42h1.79ZM13.29,5v8.52H11V8.91L8.94,11.54,6.89,8.91v4.64H4.59V5H6.95l2,3.22,2-3.22Zm4.79,16H6a1.5,1.5,0,0,1,0-3H18.08Z" transform="translate(-1.5)" /></svg></div><div class="w-50"><div class="progress" style="margin-top: 32px;"><div id="progressBar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">0%</div></div></div></div></div></div>

推荐阅读