我在 .NET core 3.1+ 中实现了这个简单的组件。 这是一个小提琴。
CSS来自bootstrap,需要显示一个空框,一个选中的框和一个“满”框以指示状态0,1,-1(可以轻松更改这些值):
<style>
[class^="icon-"], [class*=" icon-"] { display: inline-block; width: 14px; height: 14px; margin-top: 1px; *margin-right: .3em; line-height: 14px; vertical-align: text-top; background-image: url(/img/glyphicons-halflings.png); background-position: 14px 14px; background-repeat: no-repeat; }
.bootstrap-checkbox { display: inline-block; position: relative; width: 13px; height: 13px; border: 1px solid #000; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
.bootstrap-checkbox i { position: absolute; left: -2px; top: -3px; }
.icon-stop { background-position: -312px -72px; }
.icon-check { background-position: -288px 0px; }
</style>
这是 blazor 组件:
<div @ref=checkboxElement class="bootstrap-checkbox" @onclick="(e) => OnClick(e)"><i class="@ImgClass"></i></div>@Description
@code {
public ElementReference checkboxElement { get; set; }
[Parameter]
public string Description { get; set; }
[Parameter]
public bool? Checked { get; set; }
public string ImgClass { get; set; }
public int Value { get; set; }
protected override void OnInitialized()
{
Value = Checked switch { null => -1, true => 1, false => 0 };
ImgClass = Value switch { -1 => "icon-stop", 1 => "icon-check", _ => "" };
}
public void OnClick(MouseEventArgs e)
{
switch (ImgClass)
{
case "":
ImgClass = "icon-check";
Value = 1;
break;
case "icon-check":
ImgClass = "icon-stop";
Value = -1;
break;
case "icon-stop":
ImgClass = "";
Value = 0;
break;
}
}
}
使用 JS 互操作
创建一个简单的脚本
<script>
var auxiliarDOM = auxiliarDOM || {};
auxiliarDOM.setValue = function (element, property,value) {
element[property] = value;
}
</script>
然后在 blazor 中你可以有一个 ElementRef
@inject IJSRuntime JSRuntime
<input @ref="checkRef" type="checkbox" />
private ElementReference checkRef;
//this make the check indeterminate
await JSRuntime.InvokeVoidAsync("auxiliarDOM.setValue", checkRef, "indeterminate", true);
//this make the check no indeterminate
await JSRuntime.InvokeVoidAsync("auxiliarDOM.setValue", checkRef, "indeterminate", false);
工作示例:Blazor fiddle
JS设置
indeterminate
属性:
<script type="text/javascript">
function setElementProperty(element, property, value) {
element[property] = value;
}
</script>
CheckBox.razor 文件:
<input @ref=elementRef id="@elementId" type="checkbox" checked="@isChecked" @onchange="OnChange"/>
<label for="@elementId">@ChildContent</label>
CheckBox.razor.cs 文件:
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;
public partial class CheckBox
{
[Inject]
IJSRuntime jsRuntime { get; set; } = null!;
[Parameter]
public RenderFragment? ChildContent { get; set; }
[Parameter]
public bool? Checked { get; set; }
[Parameter]
public EventCallback<bool?> CheckedChanged { get; set; }
private bool isChecked;
private ElementReference elementRef;
private string elementId = Guid.NewGuid().ToString();
private async Task OnChange(ChangeEventArgs e)
{
Checked = Checked switch
{
false => true,
true => null,
null => false,
};
isChecked = Checked != false;
bool indet = Checked == null;
await jsRuntime.InvokeVoidAsync("setElementProperty", elementRef, "indeterminate", indet);
await CheckedChanged.InvokeAsync(Checked);
}
}
由于这篇文章帮助我制作了自己的三态复选框,我想分享我的实现,作为一个剃刀文件:
<input type="checkbox" @ref=@thisRef @bind=boundValue @bind:after=Change @attributes=AdditionalAttributes />
<script type="text/javascript">
function setElementProperty(element, property, value) {
element[property] = value;
}
</script>
@code {
private bool boundValue = false;
private int _value = 0;
private ElementReference thisRef = new();
public int Value
{
get => _value;
set
{
if (value < 0 || value > 2)
throw new ArgumentOutOfRangeException("Value takes values of 0, 1 and 2, where 0 is false, 1 is true and 2 is indeterminate.");
_value = value;
if (IsIndeterminate())
SetIndeterminate();
else
{
if (_value == 1)
boundValue = true;
else
boundValue = false;
}
}
}
public bool? ValueBool
{
get => Value switch
{
0 => false,
1 => true,
2 => null,
_ => throw new Exception()
};
set
{
switch (value)
{
case null:
Value = 2; break;
case true:
Value = 1; break;
case false:
Value = 0; break;
}
}
}
public bool Checked
{
get => Value == 1;
set => Value = value ? 1 : 0;
}
public StateEnum State
{
get => (StateEnum)Value;
set => Value = (int)value;
}
[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object>? AdditionalAttributes { get; set; }
public bool IsIndeterminate() => _value == 2;
private async void SetIndeterminate()
{
_value = 2;
await ijs.InvokeVoidAsync("setElementProperty", thisRef, "indeterminate", true);
}
private void Change()
{
if (boundValue)
_value = 1;
else
_value = 0;
}
public enum StateEnum
{
Unchecked,
Checked,
Indeterminate
}
}```