An automation framework to help you build Blazor component libary easier and faster.
Features
Easy and automation build parameters for component
Easy to customize and personalize component building
Easy to build a flexible dynamic component structure
Easy interoption between code and javascript
Modular implementation for automation of component building
Strong extensions and utilities of RenderTreeBuilder
Copy @inherits BlazorComponentBase
<button @attributes="AdditionalAttributes">
@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][HtmlEvent("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
Copy [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,
}
Copy <!--razor-->
<Button Color="Color.Primary">Submit</Button>
<!--html-->
<button class="btn btn-primary">Submit</button>
<!--razor-->
<Button Active Tooltip="active button" Color="Color.Information" Title="click me">Active Button</Button>
<!--html-->
<button class="btn btn-info active" data-tooltip="active button" title="click me">Active Button</button>
Copy //in app.js
export function display(){
// ...your code
}
Copy [Inject]IJSRuntime JS { get; set; }
var js = await JS.Value.ImportAsync("./app.js");
js.display(); // same as function name
Copy JS.Value.EvaluateAsync(window => {
window.console.log("log")
});
JS.Value.EvaludateAsync(@"
console.log(\"log\");
")
Copy protected override void BuildCssClass(ICssClassBuilder builder)
{
if(builder.Contains("annotation-enter"))
{
builder.Remove("annotation-exist");
}
else
{
builder.Append("annotation-enter").Append("annotation-exist");
}
}
Copy protected override void BuildAttributes(IDictionary<string, object> attributes)
{
attributes["onclick"] = HtmlHelper.Event.Create(this, ()=>{ ... });
if(attrbutes.ContainKey("data-toggle"))
{
attributes["data-toggle"] = "collapse";
}
}
Copy protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.Open("div")
.Class("my-class", (IsActive, "active"), (!string.IsNullOrEmpty(Name), "text-block"))
.Style((Size.HasValue, $"font-size:{Size}px"))
.Content("hello world")
.Close();
builder.CreateElement(10, "span", "hello", attributes: new { @class = "title-span"});
}
Copy protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.Open<Button>()
.Class("my-class", (IsActive, "active"), (!string.IsNullOrEmpty(Name), "text-block"))
.Style((Size.HasValue, $"font-size:{Size}px"))
.Content(ChildContent)
.Close();
builder.CreateComponent<NavLink>(0, "Home", new { NavLinkMatch = NavLinkMatch.All, ActiveCssClass = "nav-active" })
}
In .razor file
For List.razor
file be parent component
Copy <ul @attributes="AdditionalAttributes">
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
</ul>
For ListItem.razor
file be child of List.razor
component
Copy <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
Copy [ParentComponent] //be cascading parameter for this component
[HtmlTag("ul")]
public class List : BlazorComponentBase, IHasChildContent
{
}
For ListItem
component class
Copy [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
Copy <List>
<ListItem>...</ListItem>
</List>
<ListItem /> <!--throw exception because ListItem must be the child component of List coponent witch defined ChildComponentAttribute in ListItem-->
Copy <div class="@GetCssClass">
...
</div>
@code{
string GetCssClass => HtmlHelper.Class.Append("btn-primary").Append("active", Actived).ToString();
}
Dynamic element attribute
Copy 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... });
});
You can intercept the lifecycle of component
Copy 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}");
}
}
}
Copy builder.Services.AddComponentBuilder(configure => {
configure.Interceptors.Add(new LogInterceptor());
})
Copy Install-Package ComponentBuilder
Copy builder.Services.AddComponentBuilder();
Use ComponentBuilder.Templates
to generate a razor component library solution and online demo site
Copy dotnet new install ComponentBuilder.Templates
dotnet new blazor-sln -n {YourRazorLibraryName}