refactor: 重构 switch 组件

#Comment
支持颜色、禁用等效果、增加 ValueChanged 事件、双向绑定
This commit is contained in:
Argo Zhang 2020-03-26 23:49:59 +08:00
parent ae7e5b4a8a
commit e501da9a12
No known key found for this signature in database
GPG Key ID: 152E398953DDF19F
8 changed files with 197 additions and 229 deletions

View File

@ -4,35 +4,30 @@
<CardBodyTemplate>
<div class="form-inline">
<div class="row">
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Primary" OnText="开启" OffText="关闭" >primary</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Secondary" OnText="开启" OffText="关闭" >Secondary</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Success" OnText="开启" OffText="关闭" >Success</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Danger" OnText="开启" OffText="关闭" >Danger</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Warning" OnText="开启" OffText="关闭" >Warning</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Info" OnText="开启" OffText="关闭" >Info</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Dark" OnText="开启" OffText="关闭" >Dark</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Light" OnText="开启" OffText="关闭" >Light</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Link" OnText="开启" OffText="关闭" >Link</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnValueChanged="@OnValueChanged" Value="true" OnColor="Color.Primary" OnText="开启" OffText="关闭">primary</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnValueChanged="@OnValueChanged" Value="true" OnColor="Color.Secondary" OnText="开启" OffText="关闭">Secondary</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnValueChanged="@OnValueChanged" Value="true" OnColor="Color.Success" OnText="开启" OffText="关闭">Success</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnValueChanged="@OnValueChanged" Value="true" OnColor="Color.Danger" OnText="开启" OffText="关闭">Danger</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnValueChanged="@OnValueChanged" Value="true" OnColor="Color.Warning" OnText="开启" OffText="关闭">Warning</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnValueChanged="@OnValueChanged" Value="true" OnColor="Color.Info" OnText="开启" OffText="关闭">Info</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnValueChanged="@OnValueChanged" Value="true" OnColor="Color.Dark" OnText="开启" OffText="关闭">Dark</Switch></div>
</div>
</div>
<Logger @ref="Trace" class="mt-3" />
</CardBodyTemplate>
<CodeTemplate>
<pre>
&lt;Switch OnColor="Color.Primary" OnText="开启" OffText="关闭" &gt;Primary&lt;/Switch&gt;
&lt;Switch OnColor="Color.Secondary" OnText="开启" OffText="关闭" &gt;Secondary&lt;/Switch&gt;
&lt;Switch OnColor="Color.Success" OnText="开启" OffText="关闭" &gt;Success&lt;/Switch&gt;
&lt;Switch OnColor="Color.Danger" OnText="开启" OffText="关闭" &gt;Danger&lt;/Switch&gt;
&lt;Switch OnColor="Color.Warning" OnText="开启" OffText="关闭" &gt;Warning&lt;/Switch&gt;
&lt;Switch OnColor="Color.Info" OnText="开启" OffText="关闭" &gt;Info&lt;/Switch&gt;
&lt;Switch OnColor="Color.Dark" OnText="开启" OffText="关闭" &gt;Dark&lt;/Switch&gt;
&lt;Switch OnColor="Color.Light" OnText="开启" OffText="关闭" &gt;Light&lt;/Switch&gt;
&lt;Switch OnColor="Color.Link" OnText="开启" OffText="关闭" &gt;Link&lt;/Switch&gt;
</pre>
&lt;Switch Value="true" OnColor="Color.Primary" OnText="开启" OffText="关闭"&gt;Primary&lt;/Switch&gt;
&lt;Switch Value="true" OnColor="Color.Secondary" OnText="开启" OffText="关闭"&gt;Secondary&lt;/Switch&gt;
&lt;Switch Value="true" OnColor="Color.Success" OnText="开启" OffText="关闭"&gt;Success&lt;/Switch&gt;
&lt;Switch Value="true" OnColor="Color.Danger" OnText="开启" OffText="关闭"&gt;Danger&lt;/Switch&gt;
&lt;Switch Value="true" OnColor="Color.Warning" OnText="开启" OffText="关闭"&gt;Warning&lt;/Switch&gt;
&lt;Switch Value="true" OnColor="Color.Info" OnText="开启" OffText="关闭"&gt;Info&lt;/Switch&gt;
&lt;Switch Value="true" OnColor="Color.Dark" OnText="开启" OffText="关闭"&gt;Dark&lt;/Switch&gt;
</pre>
</CodeTemplate>
</Block>
<Block Title="开关大小" Introduction="提供开关大小应用">
<CardBodyTemplate>
<div class="form-inline">
@ -45,7 +40,6 @@
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Info" Size="Size.Small" OnText="开启" OffText="关闭" >Info</Switch></div>
</div>
</div>
</CardBodyTemplate>
<CodeTemplate>
<pre>
@ -58,40 +52,58 @@
&lt;Switch OnColor="Color.Dark" OnText="开启" OffText="关闭" &gt;Dark&lt;/Switch&gt;
&lt;Switch OnColor="Color.Light" OnText="开启" OffText="关闭" &gt;Light&lt;/Switch&gt;
&lt;Switch OnColor="Color.Link" OnText="开启" OffText="关闭" &gt;Link&lt;/Switch&gt;
</pre>
</pre>
</CodeTemplate>
</Block>
<Block Title="禁用状态" Introduction="开关不可用状态。">
<CardBodyTemplate>
<div class="form-inline">
<div class="row">
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Primary" IsDisabled="true" OnText="开启" OffText="关闭" >primary</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Primary" IsDisabled="true" OnText="开启" OffText="关闭">primary</Switch></div>
</div>
</div>
</CardBodyTemplate>
<CodeTemplate>
<pre>
&lt;Switch OnColor="Color.Primary" IsDisabled="true" OnText="开启" OffText="关闭" &gt;primary&lt;/Switch&gt;
</pre>
&lt;Switch OnColor="Color.Primary" IsDisabled="true" OnText="开启" OffText="关闭"&gt;primary&lt;/Switch&gt;
</pre>
</CodeTemplate>
</Block>
<Block Title="开关颜色" Introduction="开关颜色设置">
<Block Title="无文字控件" Introduction="不显示文字状态。">
<CardBodyTemplate>
<div class="form-inline">
<div class="row">
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch OnColor="Color.Danger" OffColor="Color.Success" OnText="开启" OffText="关闭" >开关颜色</Switch></div>
<div class="form-group col-6 col-sm-4 col-md-3 col-lg-auto"><Switch Value="true" OnColor="Color.Primary">primary</Switch></div>
</div>
</div>
</CardBodyTemplate>
<CodeTemplate>
<pre>
&lt;Switch OnColor="Color.Danger" OffColor="Color.Success" OnText="开启" OffText="关闭" &gt;开关颜色&lt;/Switch&gt;
&lt;Switch Value="true" OnColor="Color.Primary"&gt;primary&lt;/Switch&gt;
</pre>
</CodeTemplate>
</Block>
</pre>
<Block Title="双向绑定" Introduction="绑定组件内变量,数据自动同步">
<CardBodyTemplate>
<div class="form-inline">
<div class="row">
<div class="form-group col-12">
<label class="control-label">双向绑定</label>
<Switch Color="Color.Success" @bind-Value="@BindValue"></Switch>
</div>
<div class="form-group col-12">
<div>绑定数值: @BindValue</div>
</div>
</div>
</div>
</CardBodyTemplate>
<CodeTemplate>
<pre>
&lt;Switch Color="Color.Success" @@bind-Value="@@BindValue""&gt;primary&lt;/Switch&gt;
</pre>
</CodeTemplate>
</Block>

View File

@ -1,4 +1,5 @@
using BootstrapBlazor.WebConsole.Common;
using BootstrapBlazor.WebConsole.Pages.Components;
using System.Collections.Generic;
namespace BootstrapBlazor.WebConsole.Pages
@ -8,6 +9,22 @@ namespace BootstrapBlazor.WebConsole.Pages
/// </summary>
public partial class Switchs
{
/// <summary>
///
/// </summary>
protected bool BindValue { get; set; }
/// <summary>
///
/// </summary>
protected Logger? Trace { get; set; }
/// <summary>
///
/// </summary>
/// <param name="val"></param>
protected void OnValueChanged(bool val) => Trace?.Log($"Switch CurrentValue: {val}");
/// <summary>
/// 获得属性方法
/// </summary>
@ -30,20 +47,13 @@ namespace BootstrapBlazor.WebConsole.Pages
DefaultValue = " — "
},
new AttributeItem() {
Name = "ChildContent",
Description = "内容",
Type = "RenderFragment",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "IsDisabled",
Description = "是否禁用",
Type = "boolean",
ValueList = " — ",
DefaultValue = "false"
},
new AttributeItem() {
new AttributeItem() {
Name = "OnColor OffColor",
Description = "开关颜色设置",
Type = "Color",

View File

@ -83,7 +83,3 @@
<AttributeTable Items="@GetAttributes()" />
<EventTable Items="@GetEvents()" />
@code {
protected bool BindValue { get; set; }
}

View File

@ -9,6 +9,11 @@ namespace BootstrapBlazor.WebConsole.Pages
/// </summary>
public partial class Toggles
{
/// <summary>
///
/// </summary>
protected bool BindValue { get; set; }
/// <summary>
///
/// </summary>

View File

@ -1,11 +1,11 @@
@namespace BootstrapBlazor.Components
@inherits SwitchBase
<DynamicElement TagName="div" class="@ClassName" @attributes="@AdditionalAttributes">
@ChildContent
<input type="checkbox" class="custom-control-input" checked="@Value" disabled="@IsDisabled" onclick="@SwitchClick" id="@Id">
<label class="custom-control-label" for="@Id">@if (Value){@OnText}else{@OffText}</label>
</DynamicElement>
<div id="@Id" role="switch" class="@ClassName" @onclick="@OnClick" @attributes="@AdditionalAttributes">
<input type="checkbox" class="switch-input" checked="@Value" disabled="@Disabled" />
<span class="@CoreClassName" style="@StyleName"></span>
@if(!string.IsNullOrEmpty(Text))
{
<span class="switch-label"><span>@Text</span></span>
}
</div>

View File

@ -1,32 +1,54 @@
using BootstrapBlazor.Utils;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using System;
using System.Threading.Tasks;
namespace BootstrapBlazor.Components
{
/// <summary>
/// Switch 开关组件
/// </summary>
public abstract class SwitchBase : BootstrapComponentBase
public abstract class SwitchBase : ToggleBase
{
/// <summary>
/// 获得 样式集合
/// </summary>
/// <returns></returns>
protected override string? ClassName => CssBuilder.Default("switch")
.AddClass($"on-{OnColor.ToDescriptionString()}", OnColor != Color.None)
.AddClass($"off-{OffColor.ToDescriptionString()}", OffColor != Color.None)
.AddClass($"btn-{Size.ToDescriptionString()}", Size != Size.None) //设置大小生效,但是字体有问题
.AddClass("custom-control custom-switch")
.AddClass("is-checked", Value)
.AddClass("is-disabled", IsDisabled)
.AddClass(Class)
.Build();
.Build();
/// <summary>
/// 获得 开关样式集合
/// </summary>
protected string? CoreClassName => CssBuilder.Default("switch-core")
.AddClass($"border-{OnColor.ToDescriptionString()}", OnColor != Color.None && Value)
.AddClass($"bg-{OnColor.ToDescriptionString()}", OnColor != Color.None && Value)
.AddClass($"border-{OffColor.ToDescriptionString()}", OffColor != Color.None && !Value)
.AddClass($"bg-{OffColor.ToDescriptionString()}", OffColor != Color.None && !Value)
.Build();
/// <summary>
/// 获得 显示文字
/// </summary>
protected string? Text => Value ? OnText : OffText;
/// <summary>
/// 获得 开关 disabled 属性
/// </summary>
protected string? Disabled => IsDisabled ? "true" : null;
/// <summary>
/// 获得 Style 集合
/// </summary>
protected override string? StyleName => CssBuilder.Default()
.AddClass($"width: {Width}px;", Width > 0)
.AddClass($"height: {Height}px;", Height >= 20)
.Build();
/// <summary>
/// 获得/设置 开颜色
/// </summary>
[Parameter] public Color OnColor { get; set; } = Color.Info;
[Parameter] public Color OnColor { get; set; } = Color.Success;
/// <summary>
/// 获得/设置 关颜色
@ -38,75 +60,45 @@ namespace BootstrapBlazor.Components
/// </summary>
[Parameter] public Size Size { get; set; }
/// <summary>
/// 获得/设置 是否禁用
/// </summary>
[Parameter]
public bool IsDisabled { get; set; }
/// <summary>
/// 获得/设置 样式名称
/// </summary>
[Parameter] public string? Class { get; set; }
/// <summary>
/// 获得/设置 组件宽度 默认 40
/// </summary>
[Parameter]
public override int Width { get; set; } = 40;
/// <summary>
/// 获得/设置 控件高度默认 20px
/// </summary>
[Parameter] public int Height { get; set; } = 20;
/// <summary>
/// 获得/设置 组件 On 时显示文本
/// </summary>
[Parameter]
public string OnText { get; set; } = "展开";
public override string? OnText { get; set; }
/// <summary>
/// 获得/设置 组件 Off 时显示文本
/// </summary>
[Parameter]
public string OffText { get; set; } = "收缩";
public override string? OffText { get; set; }
/// <summary>
/// 获得/设置 组件是否处于 On 状态 默认为 Off 状态
/// 点击控件时触发此方法
/// </summary>
[Parameter]
public bool Value { get; set; } = true;
/// <summary>
/// 获得 开关 disabled 属性
/// </summary>
protected string? Disabled => IsDisabled ? "true" : null;
/// <summary>
/// 获得/设置 Value 值改变时回调事件
/// </summary>
[Parameter]
public EventCallback<bool> ValueChanged { get; set; }
/// <summary>
/// 转换开关事件
/// </summary>
protected EventCallback<MouseEventArgs> SwitchClick { get; set; }
/// <summary>
/// 获得 当前组件 Id
/// </summary>
[Parameter] public override string? Id { get; set; } = Guid.NewGuid().ToString();
/// <summary>
/// OnInitializedAsync 方法
/// </summary>
protected override Task OnInitializedAsync()
protected override void OnClick()
{
if (!SwitchClick.HasDelegate)
if (!IsDisabled)
{
SwitchClick = EventCallback.Factory.Create<MouseEventArgs>(this, () =>
{
Value = !Value;
ValueChanged.InvokeAsync(Value);
});
Value = !Value;
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(Value);
OnValueChanged?.Invoke(Value);
}
return Task.CompletedTask;
}
/// <summary>
/// 子组件
/// </summary>
[Parameter] public RenderFragment? ChildContent { get; set; }
}
}

View File

@ -1,6 +1,5 @@
using BootstrapBlazor.Utils;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using System;
namespace BootstrapBlazor.Components
@ -22,38 +21,38 @@ namespace BootstrapBlazor.Components
/// <summary>
/// 获得 Style 集合
/// </summary>
protected string? StyleName => CssBuilder.Default()
protected virtual string? StyleName => CssBuilder.Default()
.AddClass($"width: {Width}px;", Width > 0)
.Build();
/// <summary>
/// 获得/设置 组件
/// 获得/设置 组件
/// </summary>
[Parameter]
public int Width { get; set; } = 120;
/// <summary>
/// 获得/设置 组件 On 时显示文本
/// </summary>
[Parameter]
public string OnText { get; set; } = "展开";
public virtual int Width { get; set; } = 120;
/// <summary>
/// 获得/设置 是否禁用
/// </summary>
[Parameter] public bool IsDisabled { get; set; }
/// <summary>
/// 获得/设置 组件 On 时显示文本
/// </summary>
[Parameter]
public virtual string? OnText { get; set; } = "展开";
/// <summary>
/// 获得/设置 组件 Off 时显示文本
/// </summary>
[Parameter]
public string OffText { get; set; } = "收缩";
public virtual string? OffText { get; set; } = "收缩";
/// <summary>
/// 获得/设置 组件是否处于 On 状态 默认为 Off 状态
/// </summary>
[Parameter]
public bool Value { get; set; } = false;
public bool Value { get; set; }
/// <summary>
/// Gets or sets a callback that updates the bound value.
@ -69,7 +68,7 @@ namespace BootstrapBlazor.Components
/// <summary>
/// 点击控件时触发此方法
/// </summary>
protected void OnClick()
protected virtual void OnClick()
{
if (!IsDisabled)
{

View File

@ -327,112 +327,66 @@ a {
}
/*end toggle*/
/*start Switch*/
.on-primary .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #007bff;
background-color: #007bff;
/*switch*/
.switch {
display: inline-flex;
align-items: center;
position: relative;
font-size: 0.875rem;
line-height: 20px;
height: 20px;
vertical-align: middle;
}
.off-primary .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #007bff;
background-color: #007bff;
}
.switch .switch-input {
position: absolute;
width: 0;
height: 0;
opacity: 0;
margin: 0;
}
.on-secondary .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #6c757d;
background-color: #6c757d;
}
.switch .switch-core {
margin: 0;
display: inline-block;
position: relative;
border: 1px solid #dcdfe6;
outline: none;
border-radius: 10px;
box-sizing: border-box;
background: #dcdfe6;
cursor: pointer;
transition: border-color .3s,background-color .3s;
vertical-align: middle;
}
.off-secondary .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #6c757d;
background-color: #6c757d;
}
.switch .switch-core:after {
content: "";
position: absolute;
top: 1px;
left: 1px;
border-radius: 100%;
transition: all .3s;
width: 16px;
height: 16px;
background-color: #fff;
}
.on-success .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #28a745;
background-color: #28a745;
}
.switch.is-checked .switch-core:after {
left: 100%;
margin-left: -17px;
}
.off-success .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #28a745;
background-color: #28a745;
}
.switch .switch-label {
margin-left: 10px;
cursor: pointer;
}
.on-danger .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #dc3545;
background-color: #dc3545;
}
.switch.is-disabled {
opacity: 0.6;
}
.off-danger .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #dc3545;
background-color: #dc3545;
}
.on-warning .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #ffc107;
background-color: #ffc107;
}
.off-warning .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #ffc107;
background-color: #ffc107;
}
.on-info .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #17a2b8;
background-color: #17a2b8;
}
.off-info .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #17a2b8;
background-color: #17a2b8;
}
.on-dark .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #343a40;
background-color: #343a40;
}
.off-dark .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #343a40;
background-color: #343a40;
}
.on-light .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #f8f9fa;
background-color: #f8f9fa;
}
.off-light .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #f8f9fa;
background-color: #f8f9fa;
}
.on-link .custom-control-input:checked ~ .custom-control-label::before {
color: #fff;
border-color: #007bff;
background-color: #007bff;
}
.off-link .custom-control-input:not(:checked) ~ .custom-control-label::before {
color: #fff;
border-color: #007bff;
background-color: #007bff;
}
.switch.is-disabled, .switch.switch.is-disabled .switch-core, .switch.switch.is-disabled .switch-label {
cursor: not-allowed;
}
/*end switch*/