docs: add convention router

This commit is contained in:
ElderJames 2020-03-13 14:10:33 +08:00
parent add9e58de3
commit 8ca44d2ce5
23 changed files with 262 additions and 35 deletions

View File

@ -13,5 +13,5 @@ An enterprise-class UI components based on Ant Design and Blazor.
![](https://img.shields.io/github/workflow/status/elderjames/ant-design-blazor/Publish%20Docs?style=flat-square)
[![AntBlazor](https://img.shields.io/nuget/v/AntBlazor.svg?color=red&style=flat-square)](https://www.nuget.org/packages/AntBlazor/)
[![AntBlazor](https://img.shields.io/nuget/dt/AntBlazor.svg?style=flat-square)](https://www.nuget.org/packages/AntBlazor/)
[![AntBlazor](https://img.shields.io/github/license/ElderJames/ant-design-blazor?color=blue&style=flat-square)]()
[![AntBlazor](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](https://github.com/ElderJames/ant-design-blazor/blob/master/LICENSE)
</div>

View File

@ -12,7 +12,7 @@ namespace AntBlazor.Docs.ClientApp
builder.RootComponents.Add<App>("app");
builder.Services.AddBaseAddressHttpClient();
builder.Services.AddAntBlazor();
builder.Services.AddAntBlazorDocs();
await builder.Build().RunAsync();
}

View File

@ -21,7 +21,7 @@ namespace AntBlazor.Docs.ServerApp
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddAntBlazor();
services.AddAntBlazorDocs();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -1,4 +1,4 @@
<Router AppAssembly="@typeof(MainLayout).Assembly">
<ConventionRouter>
<Found Context="routeData">
<RouteView RouteData="routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
@ -7,4 +7,4 @@
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</ConventionRouter>

View File

@ -1,5 +1,4 @@
@page "/avatar"

<h3>Avatar</h3>
<AntAvatar size="large" icon="user" />
<AntAvatar icon="user" />

View File

@ -1,5 +1,4 @@
@page "/breadcrumb"

<h3>Breadcrumb</h3>
<h4>simple</h4>

View File

@ -1,5 +1,4 @@
@page "/button"

<AntTitle level="1">Button 按钮</AntTitle>
<AntText>按钮用于开始一个即时操作</AntText>
<AntTitle level="2">何时使用</AntTitle>

View File

@ -1,5 +1,4 @@
@page "/card"

<h3>Actions Card</h3>
<AntCard bordered Actions="new[] { actionSetting,actionEdit,actionEllipsis}" avatar="avatarTemplate">
<Title>Card</Title>

View File

@ -1,5 +1,4 @@
@page "/divider"

<h3>Divider</h3>
<h3>Horizontal</h3>

View File

@ -1,4 +1,4 @@
@page "/docs/{fileName}"

@inject HttpClient HttpClient
<Markdown>

View File

@ -1,6 +1,4 @@
@page "/error"

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>

View File

@ -1,6 +1,4 @@
@page "/icon"

<DemoCard>
<Title>基本使用</Title>
<Description>

View File

@ -1,5 +1,4 @@
@page "/"

<Markdown>
<p align="center">
<a href="https://yangshunjie.com/ant-design-blazor/">

View File

@ -1,5 +1,4 @@
@page "/switch"

<h1>Switch开关</h1>
<p>开关选择器。</p>

View File

@ -1,6 +1,4 @@
@page "/tag"

<h3>Basic Tag</h3>
<AntTag>Tag 1</AntTag>
<AntTag>

View File

@ -1,5 +1,4 @@
@page "/timeline"

<h3>Timeline</h3>
<AntTimeline mode="alternate" >

View File

@ -1,5 +1,4 @@
@page "/typography"

<h1>Typography 排版</h1>
<p>文本的基本格式</p>

View File

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Routing;
namespace AntBlazor.Docs.Routing
{
public class ConventionRouter : IComponent, IHandleAfterRender, IDisposable
{
private RenderHandle _renderHandle;
private bool _navigationInterceptionEnabled;
private string _location;
[Inject] private NavigationManager NavigationManager { get; set; }
[Inject] private INavigationInterception NavigationInterception { get; set; }
[Inject] private RouteManager RouteManager { get; set; }
[Parameter] public RenderFragment NotFound { get; set; }
[Parameter] public RenderFragment<RouteData> Found { get; set; }
public void Attach(RenderHandle renderHandle)
{
_renderHandle = renderHandle;
_location = NavigationManager.Uri;
NavigationManager.LocationChanged += HandleLocationChanged;
}
public Task SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);
if (Found == null)
{
throw new InvalidOperationException($"The {nameof(ConventionRouter)} component requires a value for the parameter {nameof(Found)}.");
}
if (NotFound == null)
{
throw new InvalidOperationException($"The {nameof(ConventionRouter)} component requires a value for the parameter {nameof(NotFound)}.");
}
RouteManager.Initialise();
Refresh();
return Task.CompletedTask;
}
public Task OnAfterRenderAsync()
{
if (!_navigationInterceptionEnabled)
{
_navigationInterceptionEnabled = true;
return NavigationInterception.EnableNavigationInterceptionAsync();
}
return Task.CompletedTask;
}
public void Dispose()
{
NavigationManager.LocationChanged -= HandleLocationChanged;
}
private void HandleLocationChanged(object sender, LocationChangedEventArgs args)
{
_location = args.Location;
Refresh();
}
private void Refresh()
{
var relativeUri = NavigationManager.ToBaseRelativePath(_location);
var parameters = ParseQueryString(relativeUri);
if (relativeUri.IndexOf('?') > -1)
{
relativeUri = relativeUri.Substring(0, relativeUri.IndexOf('?'));
}
var segments = relativeUri.Trim().Split('/', StringSplitOptions.RemoveEmptyEntries);
var matchResult = RouteManager.Match(segments);
if (matchResult.IsMatch)
{
var routeData = new RouteData(
matchResult.MatchedRoute.Handler,
parameters);
_renderHandle.Render(Found(routeData));
}
else
{
_renderHandle.Render(NotFound);
}
}
private Dictionary<string, object> ParseQueryString(string uri)
{
var querystring = new Dictionary<string, object>();
foreach (string kvp in uri.Substring(uri.IndexOf("?") + 1).Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
{
if (kvp != "" && kvp.Contains("="))
{
var pair = kvp.Split('=');
querystring.Add(pair[0], pair[1]);
}
}
return querystring;
}
}
}

View File

@ -0,0 +1,24 @@
namespace AntBlazor.Docs.Routing
{
public class MatchResult
{
public bool IsMatch { get; set; }
public Route MatchedRoute { get; set; }
public MatchResult(bool isMatch, Route matchedRoute)
{
IsMatch = isMatch;
MatchedRoute = matchedRoute;
}
public static MatchResult Match(Route matchedRoute)
{
return new MatchResult(true, matchedRoute);
}
public static MatchResult NoMatch()
{
return new MatchResult(false, null);
}
}
}

View File

@ -0,0 +1,28 @@
using System;
namespace AntBlazor.Docs.Routing
{
public class Route
{
public string[] UriSegments { get; set; }
public Type Handler { get; set; }
public MatchResult Match(string[] segments)
{
if (segments.Length != UriSegments.Length)
{
return MatchResult.NoMatch();
}
for (var i = 0; i < UriSegments.Length; i++)
{
if (string.Compare(segments[i], UriSegments[i], StringComparison.OrdinalIgnoreCase) != 0)
{
return MatchResult.NoMatch();
}
}
return MatchResult.Match(this);
}
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Components;
namespace AntBlazor.Docs.Routing
{
public class RouteManager
{
public Route[] Routes { get; private set; }
public void Initialise()
{
var pageComponentTypes = Assembly.GetExecutingAssembly()
.ExportedTypes
.Where(t => t.Namespace != null && (t.IsSubclassOf(typeof(ComponentBase))
&& t.Namespace.Contains(".Pages")));
var routesList = new List<Route>();
foreach (var pageType in pageComponentTypes)
{
if (pageType.FullName == null)
continue;
var newRoute = new Route
{
UriSegments = pageType.FullName.Substring(pageType.FullName.IndexOf("Pages", StringComparison.Ordinal) + 6).Split('.'),
Handler = pageType
};
routesList.Add(newRoute);
}
Routes = routesList.ToArray();
}
public MatchResult Match(string[] segments)
{
if (segments.Length == 0)
{
var indexRoute = Routes.SingleOrDefault(x => x.Handler.FullName != null && x.Handler.FullName.ToLower().EndsWith("index"));
return MatchResult.Match(indexRoute);
}
foreach (var route in Routes)
{
var matchResult = route.Match(segments);
if (matchResult.IsMatch)
{
return matchResult;
}
}
return MatchResult.NoMatch();
}
}
}

View File

@ -0,0 +1,16 @@
using AntBlazor.Docs.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace AntBlazor.Docs
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddAntBlazorDocs(this IServiceCollection services)
{
services.AddAntBlazor();
services.AddSingleton<RouteManager>();
return services;
}
}
}

View File

@ -4,6 +4,7 @@
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using AntBlazor
@using AntBlazor.Docs.Pages
@using AntBlazor.Docs.Shared
@using AntBlazor
@using AntBlazor.Docs.Routing
@using AntBlazor.Docs.Shared