mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-12-05 05:29:47 +08:00
!51 增加功能:日期选择框增加时间选择
* fix: 修复 Current 样式不生效问题 * fix: 修复此刻按钮不触发Value更新事件 * fix: 修复时间选择框跨越边界问题 * feat: TimePicker 组件取消按钮逻辑更新 * feat: 增加时间改变时通知前台 UI * feat: 通过 JSInvoke 得到客户端时间时刻高度 * refactor: 增加 Attribute 扩展属性 * feat: 此刻按钮时间戳根据视图来设置 * fix: 时刻格式化字符串错误 * feat: 增加确认按钮逻辑 * feat: 增加 DateTime 视图下 Header 中文本框格式化字符串配置 * style: 增加 footer 按钮样式 * feat: 增加 DateTimePicker 初始值 * feat: DatePickerBody 增加 OnValueChanged 委托 * feat: 日历组件增加 DateTime 视图模式
This commit is contained in:
parent
e76cb5ca2b
commit
257d15d421
@ -5,7 +5,7 @@
|
||||
<h4>用于选择或输入日期</h4>
|
||||
|
||||
<Block Title="选择日" Introduction="以「日」为基本单位,基础的日期选择控件" CodeFile="datepicker.1.txt">
|
||||
<DatePickerBody IsShown="true" ValueChanged="@DateValueChanged" />
|
||||
<DatePickerBody IsShown="true" OnValueChanged="@DateValueChanged" />
|
||||
|
||||
<Logger @ref="DateLogger" class="mt-3" />
|
||||
</Block>
|
||||
@ -50,14 +50,25 @@
|
||||
<Block Title="数据双向绑定" Introduction="日期组件时间改变时文本框内的数值也跟着改变" CodeFile="datepicker.4.txt">
|
||||
<div class="form-inline">
|
||||
<div class="row">
|
||||
<div class="form-group col-sm-4">
|
||||
<DateTimePicker @bind-Value="@BindValue" Placement="Placement.Right"/>
|
||||
<div class="form-group col-sm-6">
|
||||
<DateTimePicker @bind-Value="@BindValue" OnValueChanged="@DateTimeValueChanged" Placement="Placement.Right" />
|
||||
</div>
|
||||
<div class="form-group col-sm-4">
|
||||
<div class="form-group col-sm-6">
|
||||
<input class="form-control" @bind="@BindValueString" />
|
||||
</div>
|
||||
<div class="form-group col-sm-12">
|
||||
<Logger @ref="DateTimeLogger" class="mt-3" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Block>
|
||||
|
||||
<Block Title="带时间的选择器" Introduction="在同一个选择器里选择日期和时间" CodeFile="datepicker.5.txt">
|
||||
<div class="form-inline">
|
||||
<div class="row">
|
||||
<div class="form-group col-sm-4">
|
||||
<DateTimePicker ViewModel="DatePickerViewModel.DateTime" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Logger @ref="DateTimeLogger" class="mt-3" />
|
||||
</Block>
|
||||
|
@ -1,9 +1,18 @@
|
||||
@namespace BootstrapBlazor.Components
|
||||
@inherits DatePickerBodyBase
|
||||
|
||||
<div class="@ClassName" @ref="DatePickerElement">
|
||||
<div @attributes="@AdditionalAttributes" class="@ClassName" @ref="DatePickerElement">
|
||||
<div class="picker-panel-body-wrapper">
|
||||
<div class="picker-panel-body">
|
||||
<div class="@DateTimeViewClassName">
|
||||
<span class="date-picker-editor-wrap">
|
||||
<input type="text" autocomplete="off" placeholder="选择日期" class="input-inner form-control" value="@DateValueString">
|
||||
</span>
|
||||
<span class="date-picker-editor-wrap">
|
||||
<input type="text" autocomplete="off" placeholder="选择时间" class="input-inner form-control" value="@TimeValueString" @onclick="@OnClickTimeInput">
|
||||
<TimePickerBody @bind-Value="CurrentTime" OnValueChanged="OnTimeValueChanged" OnClose="@OnTimePickerClose" OnConfirm="@OnTimePickerClose" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="date-picker-header">
|
||||
<button type="button" aria-label="前一年" class="picker-panel-icon-btn" @onclick="@OnClickPrevYear">
|
||||
<i class="fa fa-angle-double-left"></i>
|
||||
@ -23,7 +32,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="picker-panel-content">
|
||||
<table cellspacing="0" cellpadding="0" class="@DateTimeViewClassName">
|
||||
<table cellspacing="0" cellpadding="0" class="@DateViewClassName">
|
||||
<tbody>
|
||||
<tr><th>日</th><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th></tr>
|
||||
@for (var week = StartDate; week < EndDate; week = week.AddDays(7))
|
||||
@ -33,7 +42,7 @@
|
||||
{
|
||||
<td class="@GetDayClass(week.AddDays(index))">
|
||||
<div>
|
||||
<DatePickerCell Value="@week.AddDays(index)" Text="@GetDayText(week.AddDays(index).Day)" OnClick="d=> OnDateTimeClick(d)" />
|
||||
<DatePickerCell Value="@week.AddDays(index)" Text="@GetDayText(week.AddDays(index).Day)" OnClick="d=> OnClickDateTime(d)" />
|
||||
</div>
|
||||
</td>
|
||||
}
|
||||
@ -67,7 +76,7 @@
|
||||
{
|
||||
<td class="@GetMonthClassName(index + row * 4 + 1)">
|
||||
<div>
|
||||
<DatePickerCell Value="@GetMonth(index + row * 4 + 1)" Text="@GetMonthText(index + row * 4 + 1)" OnClick="d => SwitchView(DatePickerViewModel.DateTime, d)" />
|
||||
<DatePickerCell Value="@GetMonth(index + row * 4 + 1)" Text="@GetMonthText(index + row * 4 + 1)" OnClick="d => SwitchView(DatePickerViewModel.Date, d)" />
|
||||
</div>
|
||||
</td>
|
||||
}
|
||||
@ -78,10 +87,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="picker-panel-footer" style="display: none;">
|
||||
<button type="button" class="button picker-panel-link-btn button--text button--mini">
|
||||
<div class="@FooterClassName">
|
||||
<button type="button" class="btn picker-panel-link-btn is-now" @onclick="@ClickNowButton">
|
||||
<span>此刻</span>
|
||||
</button><button type="button" class="button picker-panel-link-btn button--default button--mini is-plain">
|
||||
</button><button type="button" class="btn picker-panel-link-btn is-confirm" @onclick="@ClickConfirmButton">
|
||||
<span>确定</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -36,6 +36,16 @@ namespace BootstrapBlazor.Components
|
||||
/// </summary>
|
||||
protected DateTime CurrentDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected TimeSpan CurrentTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示时刻选择框
|
||||
/// </summary>
|
||||
protected bool ShowTimePicker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 组件样式
|
||||
/// </summary>
|
||||
@ -49,29 +59,36 @@ namespace BootstrapBlazor.Components
|
||||
protected string? GetDayClass(DateTime day) => CssBuilder.Default("")
|
||||
.AddClass("prev-month", day.Month < CurrentDate.Month)
|
||||
.AddClass("next-month", day.Month > CurrentDate.Month)
|
||||
.AddClass("current", day.Ticks == Value.Ticks)
|
||||
.AddClass("current", day.Ticks == CurrentDate.Ticks)
|
||||
.AddClass("today", day.Ticks == DateTime.Today.Ticks)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// 获得 年月日时分秒视图样式
|
||||
/// </summary>
|
||||
protected string? DateTimeViewClassName => CssBuilder.Default("date-picker-time-header")
|
||||
.AddClass("d-none", ViewModel != DatePickerViewModel.DateTime)
|
||||
.AddClass("is-open", ShowTimePicker)
|
||||
.Build();
|
||||
/// <summary>
|
||||
/// 获得 上一月按钮样式
|
||||
/// </summary>
|
||||
protected string? PrevMonthClassName => CssBuilder.Default("picker-panel-icon-btn pick-panel-arrow-left")
|
||||
.AddClass("d-none", ViewModel != DatePickerViewModel.DateTime)
|
||||
.AddClass("d-none", ViewModel == DatePickerViewModel.Year || ViewModel == DatePickerViewModel.Month)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// 获得 下一月按钮样式
|
||||
/// </summary>
|
||||
protected string? NextMonthClassName => CssBuilder.Default("picker-panel-icon-btn pick-panel-arrow-right")
|
||||
.AddClass("d-none", ViewModel != DatePickerViewModel.DateTime)
|
||||
.AddClass("d-none", ViewModel == DatePickerViewModel.Year || ViewModel == DatePickerViewModel.Month)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// 获得 年月日显示表格样式
|
||||
/// </summary>
|
||||
protected string? DateTimeViewClassName => CssBuilder.Default("date-table")
|
||||
.AddClass("d-none", ViewModel != DatePickerViewModel.DateTime)
|
||||
protected string? DateViewClassName => CssBuilder.Default("date-table")
|
||||
.AddClass("d-none", ViewModel == DatePickerViewModel.Year || ViewModel == DatePickerViewModel.Month)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
@ -92,7 +109,14 @@ namespace BootstrapBlazor.Components
|
||||
/// 获得 年月日显示表格样式
|
||||
/// </summary>
|
||||
protected string? CurrentMonthViewClassName => CssBuilder.Default("date-picker-header-label")
|
||||
.AddClass("d-none", ViewModel != DatePickerViewModel.DateTime)
|
||||
.AddClass("d-none", ViewModel != DatePickerViewModel.Date)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// 获得 日历 Footer 样式
|
||||
/// </summary>
|
||||
protected string? FooterClassName => CssBuilder.Default("picker-panel-footer")
|
||||
.AddClass("d-none", !ShowFooter)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
@ -104,28 +128,57 @@ namespace BootstrapBlazor.Components
|
||||
_ => $"{CurrentDate.Year} 年"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 获得 日期数值字符串
|
||||
/// </summary>
|
||||
protected string? DateValueString => CurrentDate.ToString(DateFormat);
|
||||
|
||||
/// <summary>
|
||||
/// 获得 日期数值字符串
|
||||
/// </summary>
|
||||
protected string? TimeValueString => CurrentTime.ToString(TimeFormat);
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 组件显示模式 默认为显示年月日模式
|
||||
/// </summary>
|
||||
[Parameter] public DatePickerViewModel ViewModel { get; set; }
|
||||
[Parameter] public DatePickerViewModel ViewModel { get; set; } = DatePickerViewModel.Date;
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 日期格式字符串 默认为 "yyyy-MM-dd"
|
||||
/// </summary>
|
||||
[Parameter] public string DateFormat { get; set; } = "yyyy-MM-dd";
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 日期格式字符串 默认为 "yyyy-MM-dd"
|
||||
/// </summary>
|
||||
[Parameter] public string TimeFormat { get; set; } = "hh\\:mm\\:ss";
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示本组件默认为 false 不显示
|
||||
/// </summary>
|
||||
[Parameter] public bool IsShown { get; set; }
|
||||
|
||||
private DateTime _value;
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示本组件 Footer 区域 默认不显示
|
||||
/// </summary>
|
||||
[Parameter] public bool ShowFooter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 确认按钮回调委托
|
||||
/// </summary>
|
||||
[Parameter] public Action? OnClickConfirm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 组件值
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public DateTime Value
|
||||
{
|
||||
get { return _value; }
|
||||
get { return CurrentDate.AddTicks(CurrentTime.Ticks); }
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
CurrentDate = _value;
|
||||
CurrentDate = value.Date;
|
||||
CurrentTime = value - CurrentDate;
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,6 +188,12 @@ namespace BootstrapBlazor.Components
|
||||
[Parameter]
|
||||
public EventCallback<DateTime> ValueChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 组件值改变时回调委托
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Action<DateTime>? OnValueChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
@ -193,10 +252,11 @@ namespace BootstrapBlazor.Components
|
||||
/// Day 选择时触发此方法
|
||||
/// </summary>
|
||||
/// <param name="d"></param>
|
||||
protected void OnDateTimeClick(DateTime d)
|
||||
protected void OnClickDateTime(DateTime d)
|
||||
{
|
||||
Value = d;
|
||||
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(d);
|
||||
CurrentDate = d;
|
||||
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(Value);
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -294,5 +354,56 @@ namespace BootstrapBlazor.Components
|
||||
12 => "十二月",
|
||||
_ => ""
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 时刻选择框点击时调用此方法
|
||||
/// </summary>
|
||||
protected void OnClickTimeInput()
|
||||
{
|
||||
ShowTimePicker = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击 此刻时调用此方法
|
||||
/// </summary>
|
||||
protected void ClickNowButton()
|
||||
{
|
||||
Value = ViewModel switch
|
||||
{
|
||||
DatePickerViewModel.DateTime => DateTime.Now,
|
||||
_ => DateTime.Today
|
||||
};
|
||||
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(Value);
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 时间值 改变时触发此方法
|
||||
/// </summary>
|
||||
/// <param name="ts"></param>
|
||||
protected void OnTimeValueChanged(TimeSpan ts)
|
||||
{
|
||||
CurrentTime = ts;
|
||||
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(Value);
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击 确认时调用此方法
|
||||
/// </summary>
|
||||
protected void ClickConfirmButton()
|
||||
{
|
||||
ShowTimePicker = false;
|
||||
OnClickConfirm?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected void OnTimePickerClose()
|
||||
{
|
||||
ShowTimePicker = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
@namespace BootstrapBlazor.Components
|
||||
@inherits ComponentBase
|
||||
@inherits BootstrapComponentBase
|
||||
|
||||
<a class="cell" @onclick="e => OnClick?.Invoke(Value)">@Text</a>
|
||||
<a @attributes="@AdditionalAttributes" class="cell" @onclick="e => OnClick?.Invoke(Value)">@Text</a>
|
||||
|
@ -1,12 +1,14 @@
|
||||
@namespace BootstrapBlazor.Components
|
||||
@inherits DateTimePickerBase
|
||||
|
||||
<div class="datetime-picker" @ref="Picker" data-placement="@PlacementString">
|
||||
<div @attributes="@AdditionalAttributes" class="datetime-picker" @ref="Picker" data-placement="@PlacementString">
|
||||
<div class="datetime-picker-bar">
|
||||
<input readonly="readonly" class="@ClassName" @bind="@CurrentValueAsString" placeholder="选择日期" />
|
||||
<input readonly="readonly" class="@ClassName" @bind="@CurrentValueAsString" placeholder="@PlaceholderString" />
|
||||
<span class="datetime-picker-input-icon">
|
||||
<i class="fa fa-calendar"></i>
|
||||
</span>
|
||||
</div>
|
||||
<DatePickerBody @bind-Value="@CurrentValue"></DatePickerBody>
|
||||
<DatePickerBody @bind-Value="@CurrentValue" OnValueChanged="@OnValueChanged" OnClickConfirm="@OnClickConfirm"
|
||||
ViewModel="@ViewModel" ShowFooter="@ShowFooter">
|
||||
</DatePickerBody>
|
||||
</div>
|
||||
|
@ -25,6 +25,15 @@ namespace BootstrapBlazor.Components
|
||||
.AddClass("right", Placement == Placement.Right)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// 获得 Placeholder 显示字符串
|
||||
/// </summary>
|
||||
protected string? PlaceholderString => ViewModel switch
|
||||
{
|
||||
DatePickerViewModel.DateTime => "请选择日期时间",
|
||||
_ => "请选择日期"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 获得 组件 DOM 实例
|
||||
/// </summary>
|
||||
@ -33,13 +42,38 @@ namespace BootstrapBlazor.Components
|
||||
/// <summary>
|
||||
/// 获得/设置 时间格式化字符串 默认值为 "yyyy-MM-dd"
|
||||
/// </summary>
|
||||
[Parameter] public string Format { get; set; } = "yyyy-MM-dd";
|
||||
[Parameter] public string? Format { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 弹窗位置 默认为 Auto
|
||||
/// </summary>
|
||||
[Parameter] public Placement Placement { get; set; } = Placement.Auto;
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 组件显示模式 默认为显示年月日模式
|
||||
/// </summary>
|
||||
[Parameter] public DatePickerViewModel ViewModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 组件值改变时回调方法委托
|
||||
/// </summary>
|
||||
[Parameter] public Action<DateTime> OnValueChanged { get; set; } = new Action<DateTime>(_ => { });
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 是否显示本组件 Footer 区域 默认不显示
|
||||
/// </summary>
|
||||
[Parameter] public bool ShowFooter { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized
|
||||
/// </summary>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
if (Value == DateTime.MinValue) Value = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnAfterRender 方法
|
||||
/// </summary>
|
||||
@ -56,7 +90,17 @@ namespace BootstrapBlazor.Components
|
||||
/// </summary>
|
||||
protected override string FormatValueAsString(DateTime value)
|
||||
{
|
||||
return value.ToString(Format);
|
||||
var format = Format;
|
||||
if (string.IsNullOrEmpty(format)) format = ViewModel == DatePickerViewModel.DateTime ? "yyyy-MM-dd HH:mm:ss" : "yyyy-MM-dd";
|
||||
return value.ToString(format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确认按钮点击时回调此方法
|
||||
/// </summary>
|
||||
protected void OnClickConfirm()
|
||||
{
|
||||
JSRuntime.Invoke(Picker, "datetimePicker", "hide");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
@namespace BootstrapBlazor.Components
|
||||
@inherits TimePickerBodyBase
|
||||
|
||||
<div class="time-panel" @ref="TimePickerElement">
|
||||
<div @attributes="@AdditionalAttributes" class="@ClassName" @ref="TimePickerElement">
|
||||
<div class="time-panel-content has-seconds">
|
||||
<div class="time-spinner has-seconds">
|
||||
<TimePickerCell @bind-Value="@CurrentTime" OnValueChanged="@OnValueChanged" ViewModel="TimePickerCellViewModel.Hour" />
|
||||
<TimePickerCell @bind-Value="@CurrentTime" OnValueChanged="@OnValueChanged" ViewModel="TimePickerCellViewModel.Minute" />
|
||||
<TimePickerCell @bind-Value="@CurrentTime" OnValueChanged="@OnValueChanged" ViewModel="TimePickerCellViewModel.Second" />
|
||||
<TimePickerCell @bind-Value="@CurrentTime" OnValueChanged="@OnCellValueChanged" ItemHeightCallback="@ItemHeightCallback" ViewModel="TimePickerCellViewModel.Hour" />
|
||||
<TimePickerCell @bind-Value="@CurrentTime" OnValueChanged="@OnCellValueChanged" ItemHeightCallback="@ItemHeightCallback" ViewModel="TimePickerCellViewModel.Minute" />
|
||||
<TimePickerCell @bind-Value="@CurrentTime" OnValueChanged="@OnCellValueChanged" ItemHeightCallback="@ItemHeightCallback" ViewModel="TimePickerCellViewModel.Second" />
|
||||
</div>
|
||||
<div class="time-panel-footer">
|
||||
<button type="button" class="time-panel-btn cancel" @onclick="@OnClose">取消</button>
|
||||
<button type="button" class="time-panel-btn confirm" @onclick="@OnConfirmClick">确定</button>
|
||||
<button type="button" class="time-panel-btn cancel" @onclick="@OnClickClose">取消</button>
|
||||
<button type="button" class="time-panel-btn confirm" @onclick="@OnClickConfirm">确定</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,12 +1,13 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BootstrapBlazor.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// TimePicker 组件基类
|
||||
/// </summary>
|
||||
public abstract class TimePickerBodyBase : ValidateInputBase<TimeSpan>
|
||||
public abstract class TimePickerBodyBase : BootstrapComponentBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得 组件客户端 DOM 实例
|
||||
@ -18,11 +19,46 @@ namespace BootstrapBlazor.Components
|
||||
/// </summary>
|
||||
protected TimeSpan CurrentTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 样式
|
||||
/// </summary>
|
||||
protected string? ClassName => CssBuilder.Default("time-panel")
|
||||
.AddClassFromAttributes(AdditionalAttributes)
|
||||
.Build();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the input. This should be used with two-way binding.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// @bind-Value="model.PropertyName"
|
||||
/// </example>
|
||||
[Parameter] public TimeSpan Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a callback that updates the bound value.
|
||||
/// </summary>
|
||||
[Parameter] public EventCallback<TimeSpan> ValueChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 时间刻度行高
|
||||
/// </summary>
|
||||
protected Func<double> ItemHeightCallback { get; set; } = () => 36.594d;
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 时间值改变时回调此方法
|
||||
/// </summary>
|
||||
[Parameter] public Action<TimeSpan> OnValueChanged { get; set; } = new Action<TimeSpan>(ts => { });
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 取消按钮回调委托
|
||||
/// </summary>
|
||||
[Parameter] public Action? OnClose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 确认按钮回调委托
|
||||
/// </summary>
|
||||
[Parameter] public Action? OnConfirm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OnInitialized 方法
|
||||
/// </summary>
|
||||
@ -39,28 +75,44 @@ namespace BootstrapBlazor.Components
|
||||
/// OnAfterRender 方法
|
||||
/// </summary>
|
||||
/// <param name="firstRender"></param>
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
base.OnAfterRender(firstRender);
|
||||
//await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
if (firstRender) JSRuntime.Invoke(TimePickerElement, "timepicker");
|
||||
if (firstRender && JSRuntime != null)
|
||||
{
|
||||
var height = await JSRuntime.InvokeAsync<double>(TimePickerElement, "timePicker");
|
||||
ItemHeightCallback = () => height;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ts"></param>
|
||||
protected void OnCellValueChanged(TimeSpan ts)
|
||||
{
|
||||
CurrentTime = ts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击取消按钮回调此方法
|
||||
/// </summary>
|
||||
protected void OnClose()
|
||||
protected void OnClickClose()
|
||||
{
|
||||
CurrentTime = Value;
|
||||
OnClose?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击确认按钮时回调此方法
|
||||
/// </summary>
|
||||
protected void OnConfirmClick()
|
||||
protected void OnClickConfirm()
|
||||
{
|
||||
Value = CurrentTime;
|
||||
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(Value);
|
||||
OnValueChanged?.Invoke(Value);
|
||||
OnConfirm?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
@namespace BootstrapBlazor.Components
|
||||
@inherits ComponentBase
|
||||
@inherits BootstrapComponentBase
|
||||
|
||||
<div class="time-spinner-wrapper is-arrow">
|
||||
<div @attributes="@AdditionalAttributes" class="time-spinner-wrapper is-arrow">
|
||||
<i class="time-spinner-arrow fa fa-angle-up" @onclick="OnClickUp"></i>
|
||||
<i class="time-spinner-arrow fa fa-angle-down" @onclick="OnClickDown"></i>
|
||||
<div class="time-spinner-list-wrapper">
|
||||
|
@ -59,6 +59,11 @@ namespace BootstrapBlazor.Components
|
||||
/// </summary>
|
||||
[Parameter] public Action<TimeSpan>? OnValueChanged { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 时间刻度行高
|
||||
/// </summary>
|
||||
[Parameter] public Func<double>? ItemHeightCallback { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上翻页按钮调用此方法
|
||||
/// </summary>
|
||||
@ -72,6 +77,7 @@ namespace BootstrapBlazor.Components
|
||||
_ => TimeSpan.Zero
|
||||
};
|
||||
Value = Value.Subtract(ts);
|
||||
if (Value < TimeSpan.Zero) Value = Value.Add(TimeSpan.FromHours(24));
|
||||
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(Value);
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
@ -89,16 +95,21 @@ namespace BootstrapBlazor.Components
|
||||
_ => TimeSpan.Zero
|
||||
};
|
||||
Value = Value.Add(ts);
|
||||
if (Value.Days > 0) Value = Value.Subtract(TimeSpan.FromDays(1));
|
||||
if (ValueChanged.HasDelegate) ValueChanged.InvokeAsync(Value);
|
||||
OnValueChanged?.Invoke(Value);
|
||||
}
|
||||
|
||||
private double CalcTranslateY() => 0 - ViewModel switch
|
||||
private double CalcTranslateY()
|
||||
{
|
||||
TimePickerCellViewModel.Hour => (Value.Hours - 1) * 36.6,
|
||||
TimePickerCellViewModel.Minute => (Value.Minutes - 1) * 36.6,
|
||||
TimePickerCellViewModel.Second => (Value.Seconds - 1) * 36.6,
|
||||
_ => 0
|
||||
};
|
||||
var height = ItemHeightCallback?.Invoke() ?? 36.594d;
|
||||
return 0 - ViewModel switch
|
||||
{
|
||||
TimePickerCellViewModel.Hour => (Value.Hours - 1) * height,
|
||||
TimePickerCellViewModel.Minute => (Value.Minutes - 1) * height,
|
||||
TimePickerCellViewModel.Second => (Value.Seconds - 1) * height,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,10 @@ namespace BootstrapBlazor.Components
|
||||
// 客户端组件生成后通过 invoke 生成客户端组件 id
|
||||
if (firstRender)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Id))
|
||||
if (JSRuntime != null && string.IsNullOrEmpty(Id))
|
||||
{
|
||||
// 生成 Id
|
||||
Id = await JSRuntime.GetClientIdAsync();
|
||||
Id = await JSRuntime.InvokeAsync<string>(func: "getUID");
|
||||
await InvokeAsync(StateHasChanged).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,10 @@
|
||||
/// <summary>
|
||||
/// 年月日模式
|
||||
/// </summary>
|
||||
Date,
|
||||
/// <summary>
|
||||
/// 年月日时分秒模式
|
||||
/// </summary>
|
||||
DateTime,
|
||||
/// <summary>
|
||||
/// 年视图
|
||||
|
@ -26,13 +26,6 @@ namespace BootstrapBlazor.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行客户端脚本得到一个唯一的客户端 id
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime"></param>
|
||||
/// <returns></returns>
|
||||
public static ValueTask<string> GetClientIdAsync(this IJSRuntime? jsRuntime) => jsRuntime?.InvokeAsync<string>("$.getUID") ?? new ValueTask<string>("");
|
||||
|
||||
/// <summary>
|
||||
/// 弹出 Tooltip 组件
|
||||
/// </summary>
|
||||
@ -64,5 +57,20 @@ namespace BootstrapBlazor.Components
|
||||
if (args != null) paras.AddRange(args);
|
||||
jsRuntime?.InvokeVoidAsync($"$.{func}", paras.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用 JSInvoke 方法
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime">IJSRuntime 实例</param>
|
||||
/// <param name="el">Element 实例或者组件 Id</param>
|
||||
/// <param name="func">Javascript 方法</param>
|
||||
/// <param name="args">Javascript 参数</param>
|
||||
public static async ValueTask<TValue> InvokeAsync<TValue>(this IJSRuntime jsRuntime, object? el = null, string? func = null, params object[] args)
|
||||
{
|
||||
var paras = new List<object>();
|
||||
if (el != null) paras.Add(el);
|
||||
if (args != null) paras.AddRange(args);
|
||||
return await jsRuntime.InvokeAsync<TValue>($"$.{func}", paras.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1064,6 +1064,64 @@ a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.date-picker-time-header {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #e4e4e4;
|
||||
font-size: 12px;
|
||||
padding: 8px 5px 5px;
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.date-picker-time-header .date-picker-editor-wrap {
|
||||
position: relative;
|
||||
display: table-cell;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.date-picker-time-header .date-picker-editor-wrap .input-inner {
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
padding: 0 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.date-picker-editor-wrap .time-panel {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
display: none;
|
||||
width: 145px;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.date-picker-editor-wrap .time-panel .time-spinner-item {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.date-picker-editor-wrap .time-panel-content:after, .date-picker-editor-wrap .time-panel-content:before {
|
||||
margin-top: -32px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.date-picker-editor-wrap .time-spinner-arrow.fa-angle-up {
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.date-picker-editor-wrap .time-spinner-arrow.fa-angle-down {
|
||||
bottom: 3px;
|
||||
}
|
||||
|
||||
.date-picker-editor-wrap .time-spinner-list-wrapper {
|
||||
height: 84px;
|
||||
margin: 36px 0;
|
||||
}
|
||||
|
||||
.is-open .date-picker-editor-wrap .time-panel {
|
||||
z-index: 10;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.date-picker {
|
||||
width: 322px;
|
||||
}
|
||||
@ -1358,6 +1416,35 @@ a {
|
||||
font-weight: 800;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.picker-panel-footer {
|
||||
border-top: 1px solid #e4e4e4;
|
||||
padding: 4px;
|
||||
text-align: right;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.picker-panel-footer .picker-panel-link-btn {
|
||||
padding: 7px 15px;
|
||||
font-size: 0.75rem;
|
||||
border-radius: 3px;
|
||||
line-height: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.picker-panel-footer .picker-panel-link-btn.is-confirm {
|
||||
border: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.picker-panel-footer .picker-panel-link-btn.is-confirm:hover {
|
||||
border-color: #409eff;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.picker-panel-footer .picker-panel-link-btn.is-now {
|
||||
color: #409eff;
|
||||
}
|
||||
/*end time picker*/
|
||||
|
||||
/*tabs*/
|
||||
|
@ -380,6 +380,9 @@
|
||||
$thead.css({ 'transform': 'translateY(' + top + 'px)' });
|
||||
});
|
||||
},
|
||||
timePicker: function (el) {
|
||||
return $(el).find('.time-spinner-item').height();
|
||||
},
|
||||
datetimePicker: function (el, method) {
|
||||
var $el = $(el);
|
||||
var placement = $el.attr('data-placement') || 'auto';
|
||||
@ -473,10 +476,14 @@
|
||||
// 处理点击日事件
|
||||
var $day = $el.parents('.date-table');
|
||||
if ($day.length === 1) {
|
||||
var $parent = $el.parents('.popover-datetime.show');
|
||||
var pId = $parent.attr('id');
|
||||
var $input = $('[aria-describedby="' + pId + '"]');
|
||||
if ($el.attr('aria-describedby') !== pId) $input.popover('hide');
|
||||
// 点击的是 Day cell
|
||||
var $popover = $el.parents('.popover-datetime.show');
|
||||
var $footer = $popover.find('.picker-panel-footer:visible');
|
||||
if ($footer.length === 0) {
|
||||
var pId = $popover.attr('id');
|
||||
var $input = $('[aria-describedby="' + pId + '"]');
|
||||
if ($el.attr('aria-describedby') !== pId) $input.popover('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user