- 前端
- UI组件
- 设计系统
【免费下载链接】ant-design-blazor
基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。
导读
本文围绕 ant-design-blazor 组件库中 Segmented(分段控制器)的“不可用(Disabled)”用法展开,系统讲解整体禁用、单项禁用与动态切换禁用三种实战场景,并结合仓库源码剖析禁用状态的实现原理与底层样式机制。读完本文,你将掌握如何在 Blazor 项目中通过Disabled参数精确控制 Segmented 的可用状态,并理解其背后的组件联动与交互阻断逻辑。
一、禁用场景一览:从官方 demo 出发
本指南对应仓库中的官方演示文档 disabled.md 及其配套示例 Disabled.razor。原文档的定位是“Segmented 不可用 / Disabled Segmented”,即展示分段控制器在禁用状态下的完整行为。该 demo 一共演示了四种禁用形态,覆盖了 Segmented 所有声明式配置入口:
<Segmented TValue="string" Labels="@(new []{"Map", "Transit", "Satellite"})" Disabled /> <br /> <Segmented TValue="string" Options="@options" /> <br /> <Segmented @bind-Value="_value" Disabled> <SegmentedItem Value="true" Label="True" /> <SegmentedItem Value="false" Label="False" /> </Segmented> <br /> <Segmented @bind-Value="_value" Disabled="_disabled"> <SegmentedItem Value="true" Label="True" /> <SegmentedItem Value="false" Label="False" /> </Segmented> <br /> <Switch @bind-Checked="_disabled" CheckedChildren="Disabled" UnCheckedChildren="Enable"/> @code { bool _disabled; bool _value; SegmentedOption<string>[] options = { new("Daily"), new("Weekly", "Weekly", true), new("Monthly"), new("Quarterly", "Quarterly", true ), new("Yearly"), }; }场景一:Labels模式整体禁用
<Segmented TValue="string" Labels="@(...)" Disabled />只用一个布尔属性Disabled,即可让整个分段控制器全部选项不可用。这是最直观的整体禁用写法,适合表单提交前后、权限受限、数据未就绪等场景。
场景二:Options模式单项禁用
Options接受SegmentedOption<TValue>数组。每个选项通过构造函数new("Weekly", "Weekly", true)指定三个字段:Value(值)、Label(显示文案)、Disabled(是否禁用)。在上述示例中,Weekly与Quarterly被标记为禁用,而Daily、Monthly、Yearly保持可选,实现了同一分段控制器内部分选项禁用、部分可用的混合状态。
SegmentedOption<TValue>在仓库中的定义非常精简(见 SegmentedOption.cs):
public record struct SegmentedOption<TValue>(TValue Value, string Label = null, bool Disabled = false) { public string Label { get; set; } = Label ?? Value.ToString(); }可见Label为可选参数,缺省时直接取Value的字符串表示;Disabled默认值为false。
场景三:ChildContent模式下整体禁用
当使用SegmentedItem声明子项时,同样可以在父级Segmented上直接设置Disabled,一次性禁用所有子分段项:
<Segmented @bind-Value="_value" Disabled> <SegmentedItem Value="true" Label="True" /> <SegmentedItem Value="false" Label="False" /> </Segmented>场景四:动态切换禁用状态
demo 的最后一段把Disabled绑定到可变的_disabled字段,并通过Switch组件控制:
<Segmented @bind-Value="_disabled" ... > @* 示意:Disabled 绑定变量 *@ <Switch @bind-Checked="_disabled" CheckedChildren="Disabled" UnCheckedChildren="Enable"/>当开关拨动时,Segmented 会在禁用与可用状态间实时切换,无需重建组件。这为“编辑态 / 只读态”切换、权限动态变更等交互提供了开箱即用的支持。
二、API 参数:Disabled的声明方式
根据组件官方 API 文档 index.zh-CN.md,Segmented 的核心参数如下(自v0.12.0版本提供该组件):
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| Block | 将宽度调整为父元素宽度 | boolean | false |
| DefaultValue | 默认选中的值 | TValue | - |
| Disabled | 是否禁用 | boolean | false |
| Labels | 使用字符串同时作为 Label 和 Value | string[] | - |
| OnChange | 选项变化时的回调函数 | EventCallback<TValue> | - |
| Options | 数据化配置选项内容 | TValue[] | [] |
| Size | 控件尺寸 | large|middle|small | - |
| Value | 当前选中的值 | TValue | - |
其中Disabled存在两级作用域:
- 组件级(整体禁用):设置在
Segmented<TValue>上,作用于全部选项; - 项级(单项禁用):设置在
SegmentedItem<TValue>的Disabled参数上,或通过SegmentedOption<TValue>构造函数的第三个参数指定。
三、源码剖析:禁用状态的实现原理
1. 组件级禁用:状态变更的级联传播
在 Segmented.razor.cs 中,Disabled参数并非简单赋值:
[Parameter] public bool Disabled { get => _disabled; set { if (_disabled == value) return; _disabled = value; _items.ForEach(item => item.MarkStateHasChanged()); } }当Disabled值发生变化时,组件会遍历内部维护的_items(即所有SegmentedItem)并逐个调用MarkStateHasChanged()触发重渲染,确保禁用样式与交互状态实时同步。这种“父参数变更 → 子项级联刷新”的设计正是场景四动态切换能即时生效的原因。
同时,在OnInitialized中通过ClassMapper挂载根样式类(Segmented.razor.cs):
ClassMapper.Add(PrefixCls) .If($"{PrefixCls}-lg", () => Size == SegmentedSize.Large) .If($"{PrefixCls}-sm", () => Size == SegmentedSize.Small) .If($"{PrefixCls}-disabled", () => Disabled) .If($"{PrefixCls}-block", () => Block) .If($"{PrefixCls}-rtl", () => RTL);整体禁用时根元素会获得ant-segmented-disabled类,用于承载容器级的禁用视觉反馈。
2. 项级禁用:Disabled的 OR 合并逻辑
在 SegmentedItem.razor.cs 中,单项的禁用状态由自身与父级共同决定:
protected override void OnInitialized() { base.OnInitialized(); ClassMapper.Add(PrefixCls) .If($"{PrefixCls}-selected", () => _selected) .If($"{PrefixCls}-disabled", () => Disabled || Parent?.Disabled == true); Parent?.AddItem(this); }ant-segmented-item-disabled类在自身 Disabled 或父级 Segmented.Disabled 任一为真时被加上,因此只要有一方禁用,该项即进入禁用态。
交互阻断逻辑同样遵循该 OR 规则(SegmentedItem.razor.cs):
private void OnClick() { if (Disabled || Parent.Disabled) { return; } Parent.Select(this); }点击事件处理器在禁用条件下直接return,不会触发Parent.Select(this),因此既不会更新选中值,也不会产生选中滑块(thumb)动画。
3. 三种声明入口的渲染汇聚
组件模板 Segmented.razor 按优先级渲染内容:ChildContent>Options>Labels,并依据不同入口合并禁用状态:
- 走
ChildContent(SegmentedItem)时,禁用状态由SegmentedItem.Disabled自身承担; - 走
Options时,模板写成Disabled="@(option.Disabled || Disabled)",将选项级与组件级禁用合并后传给SegmentedItem; - 走
Labels时,模板直接传递Disabled="Disabled",即所有由 Label 生成的项共享组件级禁用状态。
SegmentedItem最终渲染为<label class="ant-segmented-item ...">包裹的隐藏 radio 输入(见 SegmentedItem.razor),禁用态下该 label 失去可点击性。
四、样式层:禁用态的视觉呈现
禁用样式定义在 index.less 与 mixins.less 中:
// index.less &-item-disabled { .segmented-disabled-item(); } // mixins.less .segmented-disabled-item { &, &:hover, &:focus { color: @disabled-color; cursor: not-allowed; } }ant-segmented-item-disabled项在普通、悬浮、聚焦三种状态下均使用@disabled-color(禁用色)显示文字,并将光标改为not-allowed,从视觉上明确告知用户不可交互。此外容器级禁用时,index.less 中的 hover 背景反馈也会被取消:
&:not(&-disabled) { &:hover, &:focus { background-color: @segmented-hover-bg; } }即整体禁用(ant-segmented-disabled)时,整个控制器不再响应 hover 背景变化,进一步强化禁用语义。
五、测试佐证:渲染行为的可验证性
仓库在 SegmentedTests.razor 中提供了组件渲染测试,可验证选中项结构与 radio 输入渲染:
var cut = Context.Render(@<Segmented Labels=@(new[]{"Daily", "Weekly"}) />); cut.MarkupMatches( @<div class=" ant-segmented" id:ignore> <div class="ant-segmented-group"> <label class=" ant-segmented-item ant-segmented-item-selected" id:ignore> <input class="ant-segmented-item-input" type="radio" checked=""> ...结合前文源码可以看出:每个分段项对应一个ant-segmented-item标签与一个隐藏 radio 输入,选中项额外获得ant-segmented-item-selected类。禁用项在此基础上会追加ant-segmented-item-disabled类,并受OnClick逻辑保护,这正是编写组件级测试时可用于断言的关键标记。
六、实践要点与注意事项
- 两种粒度按需选择:若整个控制器都不允许操作,优先在
Segmented上设置Disabled;若仅部分选项不可用,则通过Options中SegmentedOption的Disabled或SegmentedItem的Disabled逐项声明。 - 禁用不影响已选值:
Disabled只阻断新的点击交互,不会清空当前的Value,已选中项在禁用态下仍保持高亮(ant-segmented-item-selected)。 - 动态切换成本极低:由于父级
Disabled的 setter 会级联触发所有子项MarkStateHasChanged(),配合Switch等控件进行只读/编辑态切换时无需手动重建选项。 - 权限与表单场景结合:可将
Disabled绑定到权限判断、表单校验结果或异步加载状态,实现数据未就绪前的占位锁定。 - 视觉与语义一致性:禁用态的最终观感由
@disabled-color主题变量控制,如需全局调整,可在 variable.less 中定制该变量,而无需改动组件代码。
本文所涉代码与文档均可在仓库对应路径直接查看:demo 元数据、demo 实现、组件实现、样式定义 与 API 文档。
- 前端
- UI组件
- 设计系统
【免费下载链接】ant-design-blazor
基于 Ant Design 与 Blazor 的前端组件库。让开发者解放生产力,实现更大价值。
相关推荐
Ant Design Blazor Segmented 组件自定义渲染:用 ChildContent 打造富内容分段控制器
Ant Design Blazor Segmented 组件自定义渲染:用 ChildContent 打造富内容分段控制器 本指南以 Ant Design Bl
UI组件前端ant-design-vue Segmented 分段控制器完全指南:API、源码原理与实战示例
ant design vue Segmented 分段控制器完全指南:API、源码原理与实战示例 导读 Segmented 是 ant design vue 中
前端UI组件设计系统Ant Design Cascader 选项禁用指南:通过 `disabled` 字段精确控制级联选择
Ant Design Cascader 选项禁用指南:通过 disabled 字段精确控制级联选择 导读 本文围绕 Ant Design 级联选择组件(Casc
前端UI组件设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考