feat(module: upload): support picture card (#438)
* feat(module: upload): Picture card demo * fix: clean code Co-authored-by: ElderJames <shunjiey@hotmail.com>
This commit is contained in:
Родитель
1f76b2afc5
Коммит
8829a233be
|
@ -1,107 +1,161 @@
|
||||||
@namespace AntDesign
|
@namespace AntDesign
|
||||||
@inherits AntDomComponentBase
|
@inherits AntDomComponentBase
|
||||||
<span class="@Class @(ListType.Equals("picture-card")? "ant-upload-picture-card-wrapper" : "")" style="@Style">
|
<span class="@Class @(ListType.Equals("picture-card")? "ant-upload-picture-card-wrapper" : "")" style="@Style">
|
||||||
|
@if (!ListType.Equals("picture-card") && ShowButton)
|
||||||
|
{
|
||||||
<div class="ant-upload ant-upload-select ant-upload-select-@(ListType)">
|
<div class="ant-upload ant-upload-select ant-upload-select-@(ListType)">
|
||||||
<input type="file" webkitdirectory="@Directory" multiple="@(Multiple || Directory)" @ref="_file" @onchange="FileNameChanged" accept="@Accept" style="display: none;" id="@_fileId" />
|
<input type="file" webkitdirectory="@Directory" multiple="@(Multiple || Directory)" @ref="_file" @onchange="FileNameChanged" accept="@Accept" style="display: none;" id="@_fileId" />
|
||||||
<span class="ant-upload" @ref="_btn" data-fileid="@_fileId">
|
<span class="ant-upload" @ref="_btn" data-fileid="@_fileId">
|
||||||
@ChildContent
|
@ChildContent
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
@if (ShowUploadList)
|
@if (ShowUploadList)
|
||||||
{
|
{
|
||||||
<div class="ant-upload-list ant-upload-list-@ListType">
|
<div class="ant-upload-list ant-upload-list-@ListType">
|
||||||
|
|
||||||
@foreach (var file in FileList)
|
@foreach (var file in FileList)
|
||||||
|
{
|
||||||
|
var tips = string.Empty;
|
||||||
|
var stateClass = string.Empty;
|
||||||
|
switch (file.State)
|
||||||
{
|
{
|
||||||
var tips = string.Empty;
|
case UploadState.Uploading:
|
||||||
var stateClass = string.Empty;
|
tips = "上传中";
|
||||||
switch (file.State)
|
break;
|
||||||
{
|
case UploadState.Fail:
|
||||||
case UploadState.Uploading:
|
tips = !string.IsNullOrWhiteSpace(file.Response) ? file.Response : "上传失败";
|
||||||
tips = "上传中";
|
stateClass = "ant-upload-list-item-error";
|
||||||
break;
|
break;
|
||||||
case UploadState.Fail:
|
case UploadState.Success:
|
||||||
tips = !string.IsNullOrWhiteSpace(file.Response) ? file.Response : "上传失败";
|
tips = file.FileName;
|
||||||
stateClass = "ant-upload-list-item-error";
|
stateClass = "ant-upload-list-item-done";
|
||||||
break;
|
break;
|
||||||
case UploadState.Success:
|
}
|
||||||
tips = file.FileName;
|
<Tooltip Title="tips" Disabled="file.State != UploadState.Fail" Style=" display: block;">
|
||||||
stateClass = "ant-upload-list-item-done";
|
<div class="@(ListType.Equals("picture-card")?"ant-upload-list-picture-card-container":""))">
|
||||||
break;
|
@if (!(ListType.Equals("picture-card") && file.State == UploadState.Uploading))
|
||||||
}
|
{
|
||||||
<Tooltip Title="tips" Disabled="file.State != UploadState.Fail" Style=" display: block;">
|
<div title="@tips" class="ant-upload-list-item @stateClass ant-upload-list-item-list-type-@ListType">
|
||||||
<div title="@tips" class="ant-upload-list-item @stateClass ant-upload-list-item-list-type-@ListType">
|
<div class="ant-upload-list-item-info">
|
||||||
<div class="ant-upload-list-item-info">
|
<span>
|
||||||
<span>
|
|
||||||
<div class="@(ListType.Equals("text")? "ant-upload-text-icon":"") @(ListType.Equals("picture") && file.State == UploadState.Fail ? "ant-upload-list-item-thumbnail ant-upload-list-item-file":"")">
|
|
||||||
@if (file.State == UploadState.Uploading)
|
|
||||||
{
|
|
||||||
<Icon Type="loading"></Icon>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ListType.Equals("picture"))
|
|
||||||
{
|
|
||||||
if (file.State == UploadState.Success)
|
|
||||||
{
|
|
||||||
<a class="ant-upload-list-item-thumbnail" href="@file.Url" target="_blank" rel="noopener noreferrer">
|
|
||||||
<img src="@(file.ObjectURL??file.Url)" alt="@file.FileName" class="ant-upload-list-item-image" />
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<Icon Type="picture" Height="1em" Width="1em" Fill="currentColor"></Icon>
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
<div class="@(ListType.Equals("text")? "ant-upload-text-icon":"") @(ListType.StartsWith("picture") && file.State == UploadState.Fail ? "ant-upload-list-item-thumbnail ant-upload-list-item-file":"")">
|
||||||
else if (ListType.Equals("text"))
|
@if (file.State == UploadState.Uploading)
|
||||||
{
|
{
|
||||||
<Icon Type="paper-clip"></Icon>
|
<Icon Type="loading"></Icon>
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
@if (ListType.Equals("text"))
|
|
||||||
{
|
|
||||||
<span class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1">
|
|
||||||
@if (file.State == UploadState.Uploading || file.State == UploadState.Fail)
|
|
||||||
{
|
|
||||||
@file.FileName
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a href="@file.Url">@file.FileName</a>
|
if (ListType.StartsWith("picture"))
|
||||||
|
{
|
||||||
|
if (file.State == UploadState.Success)
|
||||||
|
{
|
||||||
|
<a class="ant-upload-list-item-thumbnail" href="@file.Url" target="_blank" rel="noopener noreferrer">
|
||||||
|
@if (file.IsPicture())
|
||||||
|
{
|
||||||
|
<img src="@(file.ObjectURL??file.Url)" alt="@file.FileName" class="ant-upload-list-item-image" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<Icon Type="file" Height="1em" Width="1em" Fill="currentColor"></Icon>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (file.IsPicture())
|
||||||
|
{
|
||||||
|
<Icon Type="picture" Height="1em" Width="1em" Fill="currentColor"></Icon>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<Icon Type="file" Height="1em" Width="1em" Fill="currentColor"></Icon>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<Icon Type="paper-clip"></Icon>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@if (ListType.StartsWith("picture"))
|
||||||
|
{
|
||||||
|
<a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="@file.FileName" href="@file.Url">@file.FileName</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="@file.FileName">
|
||||||
|
@if (file.State == UploadState.Uploading || file.State == UploadState.Fail)
|
||||||
|
{
|
||||||
|
@file.FileName
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a href="@file.Url">@file.FileName</a>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
<span class="ant-upload-list-item@(ListType.Equals("picture-card")?"":"-card")-actions @(ListType.Equals("picture")?"picture":"")">
|
||||||
|
@if (file.State != UploadState.Uploading)
|
||||||
|
{
|
||||||
|
if (ListType.Equals("picture-card") && file.IsPicture())
|
||||||
|
{
|
||||||
|
<a target="_blank" rel="noopener noreferrer" @onclick="async ()=> { if (file.State == UploadState.Success && OnPreview.HasDelegate) await OnPreview.InvokeAsync(file); }" title="预览文件" style=" @(file.State == UploadState.Fail ? "pointer-events: none; opacity: 0.5;":"")"><Icon Type="eye" /></a>
|
||||||
|
}
|
||||||
|
<Button OnClick="(async ()=> await RemoveFile(file))"
|
||||||
|
Class="ant-btn ant-upload-list-item-card-actions-btn ant-btn-text ant-btn-sm ant-btn-icon-only">
|
||||||
|
<Icon Type="delete"></Icon>
|
||||||
|
</Button>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
}
|
|
||||||
@if (ListType.Equals("picture"))
|
|
||||||
{
|
|
||||||
<a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="@file.FileName" href="@file.Url">@file.FileName</a>
|
|
||||||
}
|
|
||||||
|
|
||||||
<span class="ant-upload-list-item-card-actions @(ListType.Equals("picture")?"picture":"")">
|
|
||||||
@if (file.State != UploadState.Uploading)
|
|
||||||
{
|
|
||||||
<Button OnClick="(async ()=> await RemoveFile(file))"
|
|
||||||
Class="ant-btn ant-upload-list-item-card-actions-btn ant-btn-text ant-btn-sm ant-btn-icon-only">
|
|
||||||
<Icon Type="delete"></Icon>
|
|
||||||
</Button>
|
|
||||||
}
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
|
||||||
|
|
||||||
@if (file.State == UploadState.Uploading)
|
</div>
|
||||||
{
|
<div class="@(ListType.Equals("picture-card") ? "ant-upload-list-item-progress" : "")">
|
||||||
<div class="ant-upload-list-item-progress">
|
@if (file.State == UploadState.Uploading)
|
||||||
<Progress Percent="file.Progress" StrokeWidth="2" Type="ProgressType.Line" ShowInfo="false"></Progress>
|
{
|
||||||
</div>
|
<div class="ant-upload-list-item-progress">
|
||||||
}
|
<Progress Percent="file.Progress" StrokeWidth="2" Type="ProgressType.Line" ShowInfo="false"></Progress>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
</Tooltip>
|
else
|
||||||
}
|
{
|
||||||
|
<div class="ant-upload-list-item ant-upload-list-item-uploading ant-upload-list-item-list-type-picture-card">
|
||||||
|
<div class="ant-upload-list-item-info">
|
||||||
|
<div class="ant-upload-list-item-thumbnail">文件上传中</div>
|
||||||
|
<span class="ant-upload-list-item-name ant-upload-list-item-name-icon-count-1" title="@file.FileName">
|
||||||
|
@file.FileName
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ant-upload-list-item-progress">
|
||||||
|
<Progress Percent="file.Progress" StrokeWidth="2" Type="ProgressType.Line" ShowInfo="false"></Progress>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
</span>
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
@if (ListType.Equals("picture-card") && ShowButton)
|
||||||
|
{
|
||||||
|
<div class="ant-upload ant-upload-select ant-upload-select-@(ListType)">
|
||||||
|
<input type="file" webkitdirectory="@Directory" multiple="@(Multiple || Directory)" @ref="_file" @onchange="FileNameChanged" accept="@Accept" style="display: none;" id="@_fileId" />
|
||||||
|
<span class="ant-upload" @ref="_btn" data-fileid="@_fileId">
|
||||||
|
@ChildContent
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
|
|
@ -75,9 +75,15 @@ namespace AntDesign
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<UploadFileItem, Task<bool>> OnRemove { get; set; }
|
public Func<UploadFileItem, Task<bool>> OnRemove { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<UploadFileItem> OnPreview { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment ChildContent { get; set; }
|
public RenderFragment ChildContent { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ShowButton { get; set; } = true;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public IJSRuntime JSRuntime { get; set; }
|
public IJSRuntime JSRuntime { get; set; }
|
||||||
|
|
||||||
|
@ -230,7 +236,7 @@ namespace AntDesign
|
||||||
await OnChange.InvokeAsync(_uploadInfo);
|
await OnChange.InvokeAsync(_uploadInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
InvokeAsync(async () => await JSRuntime.InvokeVoidAsync(JSInteropConstants.removeFileClickEventListener, _btn));
|
InvokeAsync(async () => await JSRuntime.InvokeVoidAsync(JSInteropConstants.removeFileClickEventListener, _btn));
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Text.Json;
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace AntDesign
|
namespace AntDesign
|
||||||
{
|
{
|
||||||
|
@ -25,5 +26,12 @@ namespace AntDesign
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
|
|
||||||
public ResponseModel GetResponse<ResponseModel>(JsonSerializerOptions options = null) => JsonSerializer.Deserialize<ResponseModel>(this.Response, options);
|
public ResponseModel GetResponse<ResponseModel>(JsonSerializerOptions options = null) => JsonSerializer.Deserialize<ResponseModel>(this.Response, options);
|
||||||
|
|
||||||
|
public bool IsPicture()
|
||||||
|
{
|
||||||
|
string[] imageTypes = new[] { ".jpg", ".png", ".gif", ".ico" };
|
||||||
|
Ext = FileName.Substring(FileName.LastIndexOf('.'));
|
||||||
|
return imageTypes.Contains(Ext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
@inject MessageService _message
|
||||||
|
|
||||||
|
<Upload Action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
|
||||||
|
Name="avatar"
|
||||||
|
FileList="fileList"
|
||||||
|
ShowButton="fileList.Count < 8"
|
||||||
|
ListType="picture-card"
|
||||||
|
OnPreview="(file)=> {
|
||||||
|
Console.WriteLine(file.FileName);
|
||||||
|
Console.WriteLine(file.Url);
|
||||||
|
previewVisible = true;
|
||||||
|
previewTitle = file.FileName;
|
||||||
|
imgUrl = file.Url;
|
||||||
|
}"
|
||||||
|
OnChange="HandleChange">
|
||||||
|
<div>
|
||||||
|
<Icon Type="plus"></Icon>
|
||||||
|
<div className="ant-upload-text">Upload</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</Upload>
|
||||||
|
<Modal Visible="previewVisible"
|
||||||
|
Title="previewTitle"
|
||||||
|
OnCancel="()=> previewVisible=false">
|
||||||
|
<img style="width: 100%" src="@imgUrl" />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
bool previewVisible = false;
|
||||||
|
string previewTitle = string.Empty;
|
||||||
|
string imgUrl = string.Empty;
|
||||||
|
|
||||||
|
List<UploadFileItem> fileList = new List<UploadFileItem>
|
||||||
|
{
|
||||||
|
new UploadFileItem
|
||||||
|
{
|
||||||
|
Id = "1",
|
||||||
|
FileName = "image.png",
|
||||||
|
State = UploadState.Success,
|
||||||
|
Url = "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||||
|
},
|
||||||
|
new UploadFileItem
|
||||||
|
{
|
||||||
|
Id = "2",
|
||||||
|
FileName = "image.png",
|
||||||
|
State = UploadState.Success,
|
||||||
|
Url = "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||||
|
},
|
||||||
|
new UploadFileItem
|
||||||
|
{
|
||||||
|
Id = "3",
|
||||||
|
FileName = "image.png",
|
||||||
|
State = UploadState.Success,
|
||||||
|
Url = "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||||
|
},
|
||||||
|
new UploadFileItem
|
||||||
|
{
|
||||||
|
Id = "4",
|
||||||
|
FileName = "image.png",
|
||||||
|
State = UploadState.Success,
|
||||||
|
Url = "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||||
|
},
|
||||||
|
new UploadFileItem
|
||||||
|
{
|
||||||
|
Id = "5",
|
||||||
|
FileName = "image.png",
|
||||||
|
State = UploadState.Fail
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void HandleChange(UploadInfo fileinfo)
|
||||||
|
{
|
||||||
|
if (fileinfo.File.State == UploadState.Success)
|
||||||
|
{
|
||||||
|
fileinfo.File.Url = fileinfo.File.ObjectURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ResponseModel
|
||||||
|
{
|
||||||
|
public string name { get; set; }
|
||||||
|
|
||||||
|
public string status { get; set; }
|
||||||
|
|
||||||
|
public string url { get; set; }
|
||||||
|
|
||||||
|
public string thumbUrl { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* you can make up upload button and sample style by using stylesheets */
|
||||||
|
.ant-upload-select-picture-card i {
|
||||||
|
color: #999;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-select-picture-card .ant-upload-text {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,14 @@
|
||||||
|
---
|
||||||
|
order: 3
|
||||||
|
title:
|
||||||
|
zh-CN: 照片墙
|
||||||
|
en-US: Pictures Wall
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
用户可以上传图片并在列表中显示缩略图。当上传照片数到达限制后,上传按钮消失。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
After users upload picture, the thumbnail will be shown in list. The upload button will disappear when count meets limitation.
|
Загрузка…
Ссылка в новой задаче