!852 feat(#I2C63D): add ClickToUpload mode in Upload component

* docs: 增加点击上传模式示例文件
* docs: 增加点击上传示例文档
* feat: 增加点击上传功能
* chore: 打包脚本不输出颜色
* feat: 增加单击上传模式
* chore: 增加 bundle&minifier Cli tool
* docs: 更新 Upload 示例文件
* docs: 更新 Table 示例文件
* style: upload 适配移动端
This commit is contained in:
Argo 2021-01-06 11:31:51 +08:00
parent e97d8eff21
commit 841d83b2fa
13 changed files with 199 additions and 64 deletions

View File

@ -11,20 +11,19 @@
<DetailRowTemplate>
<Tab>
<TabItem Text="明细数据">
@{
// 此段代码为提高性能
var cacheKey = context.Name ?? "";
var DetailDataSource = Enumerable.Empty<DetailRow>
();
if (Cache.ContainsKey(cacheKey))
{
DetailDataSource = Cache[cacheKey];
}
else
{
DetailDataSource = GetDetailRowsByName(cacheKey).ToList();
Cache.Add(cacheKey, DetailDataSource);
}
@{
// 此段代码为提高性能
var cacheKey = context.Name ?? "";
var DetailDataSource = Enumerable.Empty<DetailRow>();
if (Cache.ContainsKey(cacheKey))
{
DetailDataSource = Cache[cacheKey];
}
else
{
DetailDataSource = GetDetailRowsByName(cacheKey).ToList();
Cache.Add(cacheKey, DetailDataSource);
}
}
<Table TItem="DetailRow" IsBordered="true" ShowToolbar="false" Items="@DetailDataSource">
<TableColumns Context="Detail">

View File

@ -1 +1,15 @@
<Upload />
<Upload ShowDeleteButton="true" OnChange="@OnFileChange" OnDelete="@OnFileDelete"></Upload>
@code {
private Task<string> OnFileChange(InputFileChangeEventArgs args)
{
Trace?.Log($"{args.File.Name} 上传成功");
return Task.FromResult("");
}
private Task<bool> OnFileDelete(string fileName)
{
Trace?.Log($"{fileName} 成功移除");
return Task.FromResult(true);
}
}

View File

@ -1 +1 @@
<Upload ShowPreview="true"></Upload>
<Upload Style="UploadStyle.ClickToUpload" OnDelete="@(fileName => Task.FromResult(true))"></Upload>

View File

@ -1 +1,15 @@
<Upload IsCircle="true"></Upload>
@{
var DefaultFileList = new List<UploadFile>();
DefaultFileList.AddRange(new[]
{
new UploadFile()
{
FileName = "default1.jpg"
},
new UploadFile()
{
FileName = "default2.jpg"
}
});
}
<Upload Style="UploadStyle.ClickToUpload" OnDelete="@(fileName => Task.FromResult(true))" DefaultFileList="@DefaultFileList"></Upload>

View File

@ -4,15 +4,6 @@
<h4>通过点击或者拖拽上传文件</h4>
<p>
由于上传组件上传文件的大小受后台程序、反向代理等诸多因素影响,相关文章请参阅 <a href="https://gitee.com/LongbowEnterprise/BootstrapBlazor/wikis/Upload%20%E7%BB%84%E4%BB%B6%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9?sort_id=2166580" target="_blank">Upload 组件注意事项</a>
<br>出于服务器安全考虑,以下组件示例中上传文件均限制为文件类型必须为 <code>image/*</code> ,文件大小被限制为不能超过 <code>20 MB</code>
</p>
<Tips>
<p>本组件正在开发中,此页面为测试功能时使用</p>
</Tips>
<Block Title="基本用法" Introduction="与其他表单组件一起使用,显示文件名称,点击 <b>浏览</b> 按钮后选择文件并上传;通过设置 <code>ShowRemoveButton</code> 参数,显示 <b>删除</b> 按钮,点击删除按钮时回调 <code>OnDelete</code> 委托方法" CodeFile="upload.1.html">
<div class="form-inline">
<div class="row">
@ -33,6 +24,35 @@
<Logger @ref="Trace" />
</Block>
<Block Title="点击上传" Introduction="经典款式,用户点击按钮弹出文件选择框。" CodeFile="upload.2.html">
<div class="row">
<div class="col-12 col-sm-6">
<Upload Style="UploadStyle.ClickToUpload" OnDelete="@(fileName => Task.FromResult(true))"></Upload>
</div>
</div>
</Block>
<Block Title="已上传文件列表" Introduction="使用 <code>DefaultFileList</code> 设置已上传的内容" CodeFile="upload.3.html">
<div class="row">
<div class="col-12 col-sm-6">
@{
var DefaultFileList = new List<UploadFile>();
DefaultFileList.AddRange(new[]
{
new UploadFile()
{
FileName = "default1.jpg"
},
new UploadFile()
{
FileName = "default2.jpg"
}
});
}
<Upload Style="UploadStyle.ClickToUpload" OnDelete="@(fileName => Task.FromResult(true))" DefaultFileList="@DefaultFileList"></Upload>
</div>
</div>
</Block>
<!--<Block Title="预览后上传" Introduction="通过设置 <code>ShowPreview</code> 属性开启本地预览,点击上传按钮开始上传" CodeFile="upload.2.html">
<p>仅允许上传 <code>images/*</code> 格式文件,文件大小不能超过 <code>20 MB</code></p>
<Upload AllowFileType="@AllowFiles" MaxFileLength="20971520" ShowPreview="true" OnUploaded="@OnPreviewUpload"></Upload>

View File

@ -5,16 +5,32 @@
@if (Style == UploadStyle.Normal)
{
<div class="input-group">
<input type="text" class="form-control" id="@Id" readonly placeholder="@PlaceHolder" value="@FileName" />
<input type="text" class="form-control" id="@Id" readonly placeholder="@PlaceHolder" value="@(UploadFiles.FirstOrDefault()?.FileName)" />
<div class="input-group-append">
@if (ShowDeleteButton)
{
<Button class="@RemoveButtonClassString" IsDisabled="@IsDeleteButtonDisabled" Icon="@DeleteButtonIcon" Text="@DeleteButtonText" OnClick="@OnFileDelete" />
<Button class="@RemoveButtonClassString" IsDisabled="@IsDeleteButtonDisabled" Icon="@DeleteButtonIcon" Text="@DeleteButtonText" OnClick="@(e => OnFileDelete(UploadFiles.FirstOrDefault()))" />
}
@*<Button class="@UploadButtonClassString" IsDisabled="@IsDisabled" Icon="@UploadButtonIcon" Text="@UploadButtonText" />*@
<Button class="@BrowserButtonClassString" IsDisabled="@IsDisabled" Icon="@BrowserButtonIcon" Text="@BrowserButtonText" OnClick="@OnFileBrowser" />
</div>
</div>
<InputFile hidden accept="@AllowFileType" OnChange="OnFileChange" />
}
else if (Style == UploadStyle.ClickToUpload)
{
<Button class="@BrowserButtonClassString" IsDisabled="@IsDisabled" Icon="@BrowserButtonIcon" Text="@BrowserButtonText" />
<div class="upload-body">
@foreach (var item in UploadFiles)
{
<div class="@GetUploadItemClassString(item)">
<i class="@GetFileIcon(item)"></i>
<span>@item.FileName</span>
<i class="fa fa-check-circle-o text-success"></i>
<i class="fa fa-trash-o text-danger" @onclick:stopPropagation @onclick="@(e => OnFileDelete(item))"></i>
</div>
}
</div>
<InputFile hidden multiple="@MultipleString" accept="@AllowFileType" OnChange="OnFileChange" />
}
@*<div class="upload-item">
<div class="@PreviewClassString" style="@PrevStyleString">
@ -35,5 +51,4 @@
</div>
</div>
</div>*@
<InputFile hidden multiple="@MultipleString" accept="@AllowFileType" OnChange="OnFileChange" />
</div>

View File

@ -11,6 +11,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazor.Components
@ -57,6 +58,15 @@ namespace BootstrapBlazor.Components
.AddClass($"height: {Width}px;", !IsStack && IsCircle)
.Build();
private string? GetUploadItemClassString(UploadFile item) => CssBuilder.Default("upload-item")
.AddClass("is-valid", item.Code == 0)
.AddClass("is-invalid", item.Code != 0)
.Build();
private string? GetFileIcon(UploadFile item) => CssBuilder.Default("fa")
.AddClass("fa-file-text-o", true)
.Build();
/// <summary>
/// 获得/设置 圆形进度半径
/// </summary>
@ -94,7 +104,10 @@ namespace BootstrapBlazor.Components
.AddClass(BrowserButtonClass)
.Build();
private bool IsDeleteButtonDisabled => IsDisabled || string.IsNullOrEmpty(FileName);
private bool IsDeleteButtonDisabled => IsDisabled || !UploadFiles.Any();
[NotNull]
private List<UploadFile>? UploadFiles { get; set; }
/// <summary>
/// 获得/设置 上传组件模式 默认为 Normal 正常模式多用于表单中
@ -157,10 +170,11 @@ namespace BootstrapBlazor.Components
public string Icon { get; set; } = "fa fa-cloud-upload";
/// <summary>
/// 获得/设置 上传文件名
/// 获得/设置 已上传文件集合
/// </summary>
[Parameter]
public string? FileName { get; set; }
[NotNull]
public List<UploadFile>? DefaultFileList { get; set; }
/// <summary>
/// 获得/设置 是否显示预览 默认不预览
@ -306,6 +320,15 @@ namespace BootstrapBlazor.Components
ResetText ??= Localizer[nameof(ResetText)];
FileTooLargeText ??= Localizer[nameof(FileTooLargeText)];
AllowFileTypeErrorMessage ??= Localizer[nameof(AllowFileTypeErrorMessage)];
if (Style != UploadStyle.Normal)
{
UploadFiles ??= new List<UploadFile>();
}
UploadFiles ??= new List<UploadFile>();
if (DefaultFileList != null) UploadFiles.AddRange(DefaultFileList);
}
/// <summary>
@ -322,42 +345,45 @@ namespace BootstrapBlazor.Components
}
}
private async Task OnFileDelete()
private async Task OnFileDelete(UploadFile? item)
{
if (OnDelete != null && !string.IsNullOrEmpty(FileName))
if (OnDelete != null && item != null)
{
var ret = await OnDelete(FileName);
var ret = await OnDelete(item.File?.Name ?? item.FileName);
if (ret)
{
FileName = null;
UploadFiles.Remove(item);
}
}
}
private Task OnFileBrowser()
{
FileName = "";
// 单文件模式
UploadFiles.Clear();
return Task.CompletedTask;
}
private async Task OnFileChange(InputFileChangeEventArgs args)
{
FileName = args.File.Name;
if (OnChange == null)
var file = new UploadFile()
{
var format = args.File.ContentType;
var imageFile = await args.File.RequestImageFileAsync(format, 640, 480);
FileName = args.File.Name,
Size = args.File.Size,
File = args.File
};
UploadFiles.Add(file);
using var fileStream = imageFile.OpenReadStream();
using var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream);
ImageUrl = $"data:{format};base64,{Convert.ToBase64String(memoryStream.ToArray())}";
if (Style == UploadStyle.Normal)
{
if (OnChange != null)
{
ImageUrl = await OnChange(args);
}
}
else
else if (Style == UploadStyle.ClickToUpload)
{
ImageUrl = await OnChange(args);
}
}

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using Microsoft.AspNetCore.Components.Forms;
namespace BootstrapBlazor.Components
{
/// <summary>
@ -38,5 +40,10 @@ namespace BootstrapBlazor.Components
/// 获得/设置 错误信息
/// </summary>
public string? Error { get; set; }
/// <summary>
/// 获得/设置 上传文件实例
/// </summary>
internal IBrowserFile? File { get; set; }
}
}

View File

@ -2,12 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BootstrapBlazor.Components
{
/// <summary>
@ -18,8 +12,11 @@ namespace BootstrapBlazor.Components
/// <summary>
/// 正常模式
/// </summary>
Normal
Normal,
/// <summary>
/// 点击上传
/// </summary>
ClickToUpload,
}
}

File diff suppressed because one or more lines are too long

View File

@ -3640,9 +3640,52 @@ input:disabled,
/*end calendar*/
/*upload*/
.form-inline .upload {
width: calc(100% - 104px);
@media (min-width: 576px) {
.form-inline .upload {
width: 100%;
}
}
@media (min-width: 768px) {
.form-inline .upload {
width: calc(100% - 104px);
}
}
.upload .upload-body {
margin-top: 10px;
}
.upload .upload-body .upload-item {
display: flex;
align-items: center;
padding: 3px 5px;
border-radius: 3px;
transition: background-color .3s linear;
cursor: pointer;
}
.upload .upload-body .upload-item:not(:last-child) {
margin-bottom: 2px;
}
.upload .upload-body .upload-item:hover {
background-color: #ebeef5;
}
.upload .upload-body .upload-item:hover .fa-trash-o {
display: inline-block;
}
.upload .upload-body .upload-item span {
flex: 1;
padding: 0 5px;
}
.upload .upload-body .upload-item .fa-trash-o,
.upload .upload-body .upload-item:hover .fa-check-circle-o {
display: none;
}
/*end upload*/
/*divider*/

File diff suppressed because one or more lines are too long

View File

@ -43,4 +43,4 @@ var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this
$file.trigger('click');
});
};
})(jQuery);
})(jQuery);