ComponentBuilder 3.1.3
See the version list below for details.
dotnet add package ComponentBuilder --version 3.1.3
NuGet\Install-Package ComponentBuilder -Version 3.1.3
<PackageReference Include="ComponentBuilder" Version="3.1.3" />
paket add ComponentBuilder --version 3.1.3
#r "nuget: ComponentBuilder, 3.1.3"
// Install ComponentBuilder as a Cake Addin #addin nuget:?package=ComponentBuilder&version=3.1.3 // Install ComponentBuilder as a Cake Tool #tool nuget:?package=ComponentBuilder&version=3.1.3
ComponentBuilder
Easy to create a Blazor Component Library with automation features supports both razor file way and RenderTreeBuilder way.
中文介绍 | Quick Start | Document
✨ Features
- Attribute first, easy define CSS from parameters
- Easy to associate with components via Attributes
- Cusomization CSS and attributes of component by coding logic
- Both supports
.razor
file orRenderTreeBuilder
to create component - Support
Pre-definition
for components with simular parameters - Dynamic JS interoption
- New lifecycle definition of Component with interceptor design pattern
- Renderer pipeline pattern to regonize dynamic render of components
- More extensions for
RenderTreeBuilder
instance - Create element with Fluent API
🌈 Quick Start
- In
Button.razor
file
@inherits BlazorComponentBase
<button @attributes="@GetAttributes()">
@ChildContent
</button>
@code{
[CssClass("btn")]
public Button()
{
}
[Parameter][CssClass("active")]public bool Active { get; set; }
[Parameter][CssClass("btn-")]public Color? Color { get; set; }
[Parameter]public RenderFragment? ChildContent { get; set; }
[Parameter][HtmlData("tooltip")]public string? Tooltip { get; set; }
[Parameter][HtmlAttribute("onclick")]public EventCallback<ClickEventArgs> OnClick { get; set; }
[Parameter][HtmlAttribute]public string? Title { get; set; }
public enum Color
{
Primary,
Secondary,
[CssClass("info")]Information,
}
}
- In
Button.cs
component class for full automation features
[HtmlTag("button")]
[CssClass("btn")]
public class Button : BlazorComponentBase, IHasChildContent, IHasOnClick
{
[Parameter][CssClass("active")]public bool Active { get; set; }
[Parameter][CssClass("btn-")]public Color? Color { get; set; }
[Parameter]public RenderFragment? ChildContent { get; set; }
[Parameter][HtmlData("tooltip")]public string? Tooltip { get; set; }
[Parameter][HtmlEvent("onclick")]public EventCallback<ClickEventArgs> OnClick { get; set;
[Parameter][HtmlAttribute]public string? Title { get; set; }
}
public enum Color
{
Primary,
Secondary,
[CssClass("info")]Information,
}
- Use component
<Button Color="Color.Primary">Submit</Button>
<button class="btn btn-primary">Submit</button>
<Button Active Tooltip="active button" Color="Color.Information" Title="click me">Active Button</Button>
<button class="btn btn-info active" data-tooltip="active button" title="click me">Active Button</button>
🔑 JS Interoption
- Import modules
//in app.js
export function display(){
// ...your code
}
[Inject]IJSRuntime JS { get; set; }
var js = await JS.Value.ImportAsync("./app.js");
js.display(); // same as function name
- Evaluate js string
JS.Value.EvaluateAsync(window => {
window.console.log("log")
});
JS.Value.EvaludateAsync(@"
console.log(\"log\");
")
- JS invoke C# code
JS.Value.InvokeVoidAsync("myFunction", CallbackFactory.Create<string>(arg=> {
//get arg from js
}));
JS.Value.InvokeVoidAsync("calculate", CallbackFactory.Create<int,int>((arg1,arg2)=> {
//get value of arg1,arg2 from js
}))
function myFunction(dotNetRef){
dotNetRef.invokeMethodAsync("Invoke", "arg");
}
function calculate(dotNetRef){
dotNetRef.invokeMethodAsync("Invoke", 1, 2);
}
ℹ️ Logical CSS/Style/Attributes
- Logical CSS
protected override void BuildCssClass(ICssClassBuilder builder)
{
if(builder.Contains("annotation-enter"))
{
builder.Remove("annotation-exist");
}
else
{
builder.Append("annotation-enter").Append("annotation-exist");
}
}
- Logical Attributes
protected override void BuildAttributes(IDictionary<string, object> attributes)
{
attributes["onclick"] = HtmlHelper.Event.Create(this, ()=>{ ... });
if(attrbutes.ContainKey("data-toggle"))
{
attributes["data-toggle"] = "collapse";
}
}
🌴 Fluent API
builder.Div()
.Class("my-class")
.Class("active", IsActive)
.Class("text-block", !string.IsNullOrEmpty(Name))
.Style($"font-size:{Size}px", Size.HasValue)
.Content("hello world")
.Close();
builder.Component<Button>()
.Class("my-class")
.Class("active", IsActive)
.Class("text-block", !string.IsNullOrEmpty(Name))
.Style((Size.HasValue, $"font-size:{Size}px"))
.Content(ChildContent)
.Close();
builder.Ul().ForEach("li", result => {
result.attribute.Content($"content{result.index}");
});
🚸 Component Association
In .razor file
- For
List.razor
file be parent component
<ul @attributes="@GetAttributes()">
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
</ul>
- For
ListItem.razor
file be child ofList.razor
component
<li @attributes="AdditionalAttributes">@ChildContent</li>
@code{
[ChildComponent(typeof(List))]
public ListItem()
{
}
[CascadingParameter] public List CascadedList { get; set; }
[Parameter] public RenderFragment? ChildContent { get; set; }
}
In RenderTreeBuilder
- For
List
component class
[ParentComponent] //be cascading parameter for this component
[HtmlTag("ul")]
public class List : BlazorComponentBase, IHasChildContent
{
}
- For
ListItem
component class
[ChildComponent(typeof(List))] //Strong association with List
[HtmlTag("li")]
public class ListItem : BlazorComponentBase, IHasChildContent
{
[CascadingParameter]public List CascadedList { get; set; }
[Parameter] public RenderFragment? ChildContent { get; set; }
}
Use in blazor
<List>
<ListItem>...</ListItem>
</List>
<ListItem />
🔯 HtmlHelper
- 在
.razor
中
<div class="@GetCssClass"></div>
@code{
string GetCssClass => HtmlHelper.Class.Append("btn-primary").Append("active", Actived).ToString();
}
builder.CreateElement(0, "span", attributes:
new {
@class = HtmlHelper.Class
.Append("btn-primary")
.Append("active", Actived),
style = HtmlHelper.Style.Append($"width:{Width}px"),
onclick = HtmlHelper.Event.Create<MouseEventArgs>(this, e=>{ //...click... });
});
⚔️ Interceptors
You can intercept the lifecycle of component
- Define an interceptor
public class LogInterceptor : ComponentInterceptorBase
{
private readonly ILogger<LogInterceptor> _logger;
public LogInterceptor(ILogger<LogInterceptor> logger)
{
_logger = logger;
}
//Run in SetParameterAsync method is called
public override void InterceptSetParameters(IBlazorComponent component, ParameterView parameters)
{
foreach(var item in parameters)
{
_logger.LogDebug($"Key:{item.Name}, Value:{item.Value}");
}
}
}
- Register interceptor
builder.Services.AddComponentBuilder(configure => {
configure.Interceptors.Add(new LogInterceptor());
})
♻️ Renderer Pipeline
Recognize special case to render specified component
public class NavLinkComponentRender : IComponentRender
{
public bool Render(IBlazorComponent component, RenderTreeBuilder builder)
{
if ( component is IHasNavLink navLink )
{
builder.OpenComponent<NavLink>(0);
builder.AddAttribute(1, nameof(NavLink.Match), navLink.Match);
builder.AddAttribute(2, nameof(NavLink.ActiveClass), navLink.ActiveCssClass);
builder.AddAttribute(3, nameof(NavLink.ChildContent), navLink.ChildContent);
builder.AddMultipleAttributes(4, component.GetAttributes());
builder.CloseComponent();
return false;
}
return true;
}
}
- Register renderer in configuration
builder.Services.AddComponentBuilder(configure => {
configure.Renderers.Add(typeof(NavLinkComponentRenderer));
});
📘 Installation Guide
- Install from
Nuget.org
Install-Package ComponentBuilder
- Register service
builder.Services.AddComponentBuilder();
Read document for more informations
📝 Component Library Solution Template
Use ComponentBuilder.Templates
to generate a razor component library solution and online demo site
dotnet new install ComponentBuilder.Templates
dotnet new blazor-sln -n {YourRazorLibraryName}
More information see templates
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Microsoft.AspNetCore.Components.Web (>= 6.0.0)
- Microsoft.JSInterop (>= 6.0.0)
- OneOf (>= 3.0.223)
-
net7.0
- Microsoft.AspNetCore.Components.Web (>= 7.0.0)
- Microsoft.JSInterop (>= 7.0.0)
- OneOf (>= 3.0.223)
NuGet packages (5)
Showing the top 5 NuGet packages that depend on ComponentBuilder:
Package | Downloads |
---|---|
TDesign
基于腾讯 TDesign 的 Blazor 企业级组件库。腾讯 TDesign 官方地址:https://tdesign.tencent.com/ |
|
BlamanticUI
The css framework from Semantic-UI for blazor without jQuery. |
|
ComponentBuilder.FluentRenderTree
用链式编程的方式简化 RenderTreeBuilder 的操作。 示例: builder.Element("div").Content("hello").Close(); builder.Component<Button>().Content("Button").Close(); builder.Div(Id is not null).Content(content => content.Component<Icon>().Attribute(m => m.Name, "user").Close()).Close(); |
|
ComponentBuilder.Interceptors.Diagnostics.Console
在控制台中用于组件生命周期诊断的拦截器,该拦截器可以用于调试阶段的生命周期运行的输出。 |
|
ComponentBuilder.Resolvers.FluentClass
组件参数支持 IFluentClassProvider 自动解析成 CSS 类。 [Parameter]public IFluentClassProvider Parameter{ get; set; } <Component Parameter="Provider.Is3.FromTop.HasSmall" /> |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on ComponentBuilder:
Repository | Stars |
---|---|
tdesign-blazor/TDesignBlazor
基于腾讯 TDesign 的 Blazor 组件库
|
Version | Downloads | Last updated |
---|---|---|
5.1.0 | 129 | 3/7/2024 |
5.0.0 | 186 | 12/21/2023 |
5.0.0-beta-1 | 155 | 11/16/2023 |
4.1.2 | 1,001 | 7/17/2023 |
4.1.1 | 200 | 7/17/2023 |
4.1.0 | 743 | 6/4/2023 |
4.0.0 | 479 | 5/30/2023 |
4.0.0-beta-3 | 257 | 5/22/2023 |
4.0.0-beta-2 | 138 | 5/19/2023 |
4.0.0-beta-1 | 143 | 5/17/2023 |
3.1.4 | 529 | 3/17/2023 |
3.1.3 | 196 | 3/16/2023 |
3.1.0 | 213 | 3/10/2023 |
3.0.0 | 737 | 2/24/2023 |
3.0.0-beta-0217 | 100 | 2/16/2023 |
3.0.0-beta-0206 | 183 | 2/6/2023 |
3.0.0-beta-0130 | 110 | 1/30/2023 |
3.0.0-beta-0114 | 117 | 1/13/2023 |
2.3.0 | 297 | 12/28/2022 |
2.2.0 | 293 | 12/13/2022 |
2.1.0 | 1,450 | 11/24/2022 |
2.0.0 | 361 | 10/28/2022 |
1.5.0.4 | 373 | 10/18/2022 |
1.5.0.3 | 391 | 10/13/2022 |
1.5.0.2 | 1,219 | 10/5/2022 |
1.5.0.1 | 393 | 10/3/2022 |
1.5.0 | 400 | 10/1/2022 |
1.4.1.1 | 664 | 9/19/2022 |
1.4.1 | 404 | 9/16/2022 |
1.4.0 | 416 | 9/15/2022 |
1.3.0 | 413 | 8/29/2022 |
1.2.1 | 575 | 7/12/2022 |
1.2.0 | 411 | 7/11/2022 |
1.1.0 | 555 | 5/22/2022 |
1.0.0 | 610 | 3/23/2022 |
0.7.0 | 438 | 3/11/2022 |
0.6.0 | 436 | 2/9/2022 |
0.5.0 | 270 | 1/6/2022 |
0.4.0 | 280 | 12/23/2021 |
0.3.0 | 293 | 12/16/2021 |
0.2.0 | 300 | 12/7/2021 |
0.1.0 | 6,146 | 11/24/2021 |