From e9916371b54005579b5c4269df1ad04984cf6543 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 8 Mar 2023 04:26:48 -0800 Subject: [PATCH] feat: add AddTabItemBindOptions service (#647) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 增加 AddTabItemMenuBindOption 服务 * doc: 增加 ConfigureTabItemBindOptions 配置示例 * feat: 增加 TabItemMenuBindOptions 逻辑 * doc: 移除 TabItemOptionAttribute 标签 * fix: 修复地址由于 / 导致比对结果不一致问题 * test: 增加 ConfigureTabItemBindOptions 单元测试 * refactor: 重命名配置服务 * chore: bump version 7.4.2-beta04 * refactor: rename TabItemMenuBindOptions --- src/BootstrapBlazor.Server/Program.cs | 7 +++ .../Samples/LayoutDemo.razor | 1 - src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- .../Components/Tab/Tab.razor.cs | 48 ++++++++----------- ...tstrapBlazorServiceCollectionExtensions.cs | 25 ++++++++++ .../Options/TabItemMenuBindOptions.cs | 16 +++++++ test/UnitTest/Components/TabTest.cs | 15 +++++- test/UnitTest/Core/TabTestBase.cs | 7 +++ test/UnitTest/Pages/Binder.cs | 16 +++++++ 9 files changed, 106 insertions(+), 31 deletions(-) create mode 100644 src/BootstrapBlazor/Options/TabItemMenuBindOptions.cs create mode 100644 test/UnitTest/Pages/Binder.cs diff --git a/src/BootstrapBlazor.Server/Program.cs b/src/BootstrapBlazor.Server/Program.cs index 8c841668fe0..d6b318f6516 100644 --- a/src/BootstrapBlazor.Server/Program.cs +++ b/src/BootstrapBlazor.Server/Program.cs @@ -35,6 +35,13 @@ builder.Services.Configure(option => option.MaximumReceiveMessageSize = null); +builder.Services.ConfigureTabItemMenuBindOptions(options => +{ + options.Binders.Add("layout-demo", new() { Text = "Text 1" }); + options.Binders.Add("layout-demo?text=Parameter", new() { Text = "Text 2" }); + options.Binders.Add("layout-demo/text=Parameter", new() { Text = "Text 3" }); +}); + var app = builder.Build(); // 启用本地化 diff --git a/src/BootstrapBlazor.Shared/Samples/LayoutDemo.razor b/src/BootstrapBlazor.Shared/Samples/LayoutDemo.razor index a5c26b7d403..25803029f1d 100644 --- a/src/BootstrapBlazor.Shared/Samples/LayoutDemo.razor +++ b/src/BootstrapBlazor.Shared/Samples/LayoutDemo.razor @@ -1,7 +1,6 @@ @page "/layout-demo" @page "/layout-demo/{title?}" @layout PageLayout -@attribute [TabItemOption(Text = "示例网页", Icon = "fa-fw fa-solid fa-laptop")]

测试路径:

diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index e99f8fe288f..38abdadbd95 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@ - 7.4.2-beta03 + 7.4.2-beta04 diff --git a/src/BootstrapBlazor/Components/Tab/Tab.razor.cs b/src/BootstrapBlazor/Components/Tab/Tab.razor.cs index bf553cf9b0d..5fe9e4d7938 100644 --- a/src/BootstrapBlazor/Components/Tab/Tab.razor.cs +++ b/src/BootstrapBlazor/Components/Tab/Tab.razor.cs @@ -3,6 +3,7 @@ // Website: https://www.blazor.zone or https://argozhang.github.io/ using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; using System.Collections.Concurrent; using System.Reflection; @@ -213,6 +214,10 @@ public partial class Tab : IHandlerException, IDisposable [NotNull] private TabItemTextOptions? Options { get; set; } + [Inject] + [NotNull] + private IOptionsMonitor? TabItemMenuBinder { get; set; } + private ConcurrentDictionary LazyTabCache { get; } = new(); /// @@ -455,22 +460,26 @@ private void AddTabItem(string url) if (context.Handler != null) { // 检查 Options 优先 - var option = context.Handler.GetCustomAttribute(false); - if (Options.Valid()) + var option = context.Handler.GetCustomAttribute(false) + ?? TabItemMenuBinder.CurrentValue.Binders + .FirstOrDefault(i => i.Key.TrimStart('/').Equals(url.TrimStart('/'), StringComparison.OrdinalIgnoreCase)) + .Value; + if (option != null) { - AddParameters(option); + parameters.Add(nameof(TabItem.Icon), option.Icon); + parameters.Add(nameof(TabItem.Closable), option.Closable); + parameters.Add(nameof(TabItem.IsActive), true); + parameters.Add(nameof(TabItem.Text), option.Text); } - else + else if (Options.Valid()) { - if (option != null) - { - parameters.Add(nameof(TabItem.Icon), option.Icon); - parameters.Add(nameof(TabItem.Closable), option.Closable); - parameters.Add(nameof(TabItem.IsActive), true); - } - parameters.Add(nameof(TabItem.Text), option?.Text ?? url.Split("/").FirstOrDefault()); - parameters.Add(nameof(TabItem.Url), url); + parameters.Add(nameof(TabItem.Icon), Options.Icon); + parameters.Add(nameof(TabItem.Closable), Options.Closable); + parameters.Add(nameof(TabItem.IsActive), Options.IsActive); + parameters.Add(nameof(TabItem.Text), Options.Text); + Options.Reset(); } + parameters.Add(nameof(TabItem.Url), url); parameters.Add(nameof(TabItem.ChildContent), new RenderFragment(builder => { @@ -491,21 +500,6 @@ private void AddTabItem(string url) } AddTabItem(parameters); - - void AddParameters(TabItemOptionAttribute? option) - { - var text = option?.Text ?? Options.Text; - var icon = option?.Icon ?? Options.Icon ?? string.Empty; - var active = Options.IsActive; - var closable = option?.Closable ?? Options.Closable; - Options.Reset(); - - parameters.Add(nameof(TabItem.Url), url); - parameters.Add(nameof(TabItem.Icon), icon); - parameters.Add(nameof(TabItem.Closable), closable); - parameters.Add(nameof(TabItem.IsActive), active); - parameters.Add(nameof(TabItem.Text), text); - } } /// diff --git a/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs b/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs index c347106f62e..4bb79741952 100644 --- a/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs +++ b/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs @@ -58,6 +58,8 @@ public static IServiceCollection AddBootstrapBlazor(this IServiceCollection serv services.ConfigureBootstrapBlazorOption(configureOptions); services.ConfigureIPLocatorOption(); + + services.AddTabItemBindOptions(); return services; } @@ -140,4 +142,27 @@ public static IServiceCollection AddOptionsMonitor(this IServiceCollec services.TryAddSingleton, ConfigureOptions>(); return services; } + + /// + /// 增加 菜单与标签捆绑类配置项服务 + /// + /// + /// + static IServiceCollection AddTabItemBindOptions(this IServiceCollection services) + { + services.AddOptionsMonitor(); + return services; + } + + /// + /// 增加第三方菜单路由与 Tab 捆绑字典配置 + /// + /// + /// + /// + public static IServiceCollection ConfigureTabItemMenuBindOptions(this IServiceCollection services, Action configureOptions) + { + services.Configure(configureOptions); + return services; + } } diff --git a/src/BootstrapBlazor/Options/TabItemMenuBindOptions.cs b/src/BootstrapBlazor/Options/TabItemMenuBindOptions.cs new file mode 100644 index 00000000000..8bf0494d260 --- /dev/null +++ b/src/BootstrapBlazor/Options/TabItemMenuBindOptions.cs @@ -0,0 +1,16 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +namespace BootstrapBlazor.Components; + +/// +/// 标签与菜单捆绑配置项 +/// +public class TabItemBindOptions +{ + /// + /// 获得/设置 集合 + /// + public Dictionary Binders { get; set; } = new(); +} diff --git a/test/UnitTest/Components/TabTest.cs b/test/UnitTest/Components/TabTest.cs index 1ec57699f9c..46e69567d0d 100644 --- a/test/UnitTest/Components/TabTest.cs +++ b/test/UnitTest/Components/TabTest.cs @@ -524,7 +524,7 @@ public void TabItem_HeaderTemplate() } [Fact] - public async Task TabItemOption_Ok() + public void TabItemOptions_Ok() { var cut = Context.RenderComponent(pb => { @@ -535,8 +535,19 @@ public async Task TabItemOption_Ok() pb.Add(a => a.ShowClose, true); pb.Add(a => a.DefaultUrl, "/Dog"); }); - await cut.InvokeAsync(() => cut.Instance.AddTab("/Dog", "Dog")); + cut.InvokeAsync(() => cut.Instance.AddTab("/Dog", "Dog")); var tabItem = cut.FindComponents().First(i => i.Markup.Contains("Dog")); Assert.DoesNotContain("tabs-item-close", tabItem.Markup); } + + [Fact] + public void TabItemMenuBinder_Ok() + { + var cut = Context.RenderComponent(pb => + { + pb.Add(a => a.AdditionalAssemblies, new Assembly[] { GetType().Assembly }); + pb.Add(a => a.DefaultUrl, "/Binder"); + }); + cut.Contains("Index_Binder_Test"); + } } diff --git a/test/UnitTest/Core/TabTestBase.cs b/test/UnitTest/Core/TabTestBase.cs index bb3130b65e9..cb0ca88389f 100644 --- a/test/UnitTest/Core/TabTestBase.cs +++ b/test/UnitTest/Core/TabTestBase.cs @@ -48,6 +48,13 @@ protected virtual void ConfigureServices(IServiceCollection services) { services.AddBootstrapBlazor(op => op.ToastDelay = 2000); services.ConfigureJsonLocalizationOptions(op => op.AdditionalJsonAssemblies = new[] { typeof(Alert).Assembly }); + services.ConfigureTabItemMenuBindOptions(options => + { + options.Binders = new() + { + { "/Binder", new() { Text = "Index_Binder_Test" } } + }; + }); } protected virtual void ConfigureConfigration(IServiceCollection services) diff --git a/test/UnitTest/Pages/Binder.cs b/test/UnitTest/Pages/Binder.cs new file mode 100644 index 00000000000..79c11c6fa9a --- /dev/null +++ b/test/UnitTest/Pages/Binder.cs @@ -0,0 +1,16 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using Microsoft.AspNetCore.Components.Rendering; + +namespace UnitTest.Pages; + +[Route("/Binder")] +public class Binder : ComponentBase +{ + protected override void BuildRenderTree(RenderTreeBuilder builder) + { + builder.AddContent(0, "Binder"); + } +}