!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:
Argo 2020-04-23 22:05:55 +08:00
parent e76cb5ca2b
commit 257d15d421
15 changed files with 413 additions and 67 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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");
}
}
}

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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">

View File

@ -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
};
}
}
}

View File

@ -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);
}
}

View File

@ -8,6 +8,10 @@
/// <summary>
/// 年月日模式
/// </summary>
Date,
/// <summary>
/// 年月日时分秒模式
/// </summary>
DateTime,
/// <summary>
/// 年视图

View File

@ -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());
}
}
}

View File

@ -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*/

View File

@ -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');
}
}
}
});