Enterprise-level component library based on Bootstrap and Blazor

star nuget master download license repo commit

Upload 上传

通过点击上传文件

InputUpload 组件与其他表单组件一起使用,显示文件名称,点击 浏览 按钮后选择文件并上传;通过设置 ShowRemoveButton 参数,显示 删除 按钮,点击删除按钮时回调 OnDelete 委托方法

Demo

在表单内使用文件上传组件对文件格式进行约束

Demo
  • 使用 ValidateForm 表单组件,通过设置模型属性的 FileValidation 标签设置自定义验证,支持文件 扩展名 大小 验证,本例中设置扩展名为 .png .jpg .jpeg,文件大小限制为 50K
  • 选择文件后并未开始上传文件,点击 提交 按钮数据验证合法后,再 OnSubmit 回调委托中进行上传文件操作,注意 Picture 属性类型为 IBrowserFile

ButtonUpload 组件,经典款式,用户点击按钮弹出文件选择框。

Demo

点击 浏览按钮 选择文件上传,本例中设置 IsMultiple=true 可多选文件进行上传

设置 IsSingle 时,仅可以上传一张图片或者文件

使用 DefaultFileList 设置已上传的内容

Demo
Test.xls (0 B)
Test.doc (0 B)
Test.ppt (0 B)
Test.mp3 (0 B)
Test.mp4 (0 B)
Test.pdf (0 B)
Test.cs (0 B)
Test.zip (0 B)
Test.txt (0 B)
Test.dat (0 B)

使用 DefaultFileList 设置已上传的内容

Demo

AvatarUpload 组件,使用 OnChange 限制用户上传的图片格式和大小。本例中仅允许上传 jpg/png/bmp/jpeg/gif 五种图片格式

Demo

卡片形式头像框

圆形头像框

设置 IsSingle 时,仅可以上传一张图片或者文件

组件提供了 Accept 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 Accept="image/gif, image/jpeg",如果不限制图像的格式,可以写为:Accept="image/*",该属性并不安全还是应该是使用 服务器端验证 进行文件格式验证

相关文档:[Accept 属性详解] [Media Types 详细列表]

通过 DefaultFileList 属性设置预览地址 PrevUrl 即可

验证表单内使用头像框示例

CardUpload 组件,呈现为卡片式带预览模式

Demo

SSR 模式
Server Side 模式中可以使用 IWebHostEnvironment 注入服务获取到 wwwwroot 目录,保存文件到 images\uploader 中,此功能无需 MVC 的控制器辅助进行文件的保存,直接调用 SaveToFile 方法即可
Wasm 模式
wasm 模式中无法使用 IWebHostEnvironment 需要调用 webapi 接口等形式将文件保存到服务器端
有兴趣的同学可以通过开源仓库中的 wiki 文档中相关资源查看关于 Upload 组件的相关知识技巧 [传送门]
本例中通过服务器端验证当文件大小超过 200MB 时,提示文件太大提示信息

本例中设置 ShowProgress=true 显示上传进度条

设置 IsSingle 时,仅可以上传一张图片或者文件

不同文件格式显示的图标不同

Demo
Test.xls (0 B)
Test.doc (0 B)
Test.ppt (0 B)
Test.mp3 (0 B)
Test.mp4 (0 B)
Test.pdf (0 B)
Test.cs (0 B)
Test.zip (0 B)
Test.txt (0 B)
Test.dat (0 B)

InputUpload

Loading...

ButtonUpload/CardUpload

Loading...

AvatarUpload

Loading...
@page "/uploads"

<h3>Upload 上传</h3>

<h4>通过点击上传文件</h4>

<Block Title="基本用法" Introduction="<code>InputUpload</code> 组件与其他表单组件一起使用,显示文件名称,点击 <b>浏览</b> 按钮后选择文件并上传;通过设置 <code>ShowRemoveButton</code> 参数,显示 <b>删除</b> 按钮,点击删除按钮时回调 <code>OnDelete</code> 委托方法">
    <div class="row g-3">
        <div class="col-12 col-sm-6">
            <label for="text1" class="form-label">姓名:</label>
            <input id="text1" class="form-control">
        </div>
        <div class="col-12 col-sm-6">
            <label for="text2" class="form-label">地址:</label>
            <input id="text2" class="form-control">
        </div>
        <div class="col-12">
            <label for="text3" class="form-label">照片:</label>
            <InputUpload TValue="string" Id="text3" ShowDeleteButton="true" OnChange="@OnFileChange" OnDelete="@OnFileDelete"></InputUpload>
        </div>
    </div>
    <BlockLogger @ref="Trace" class="mt-3" />
</Block>

<Block Title="表单应用" Introduction="在表单内使用文件上传组件对文件格式进行约束">
    <ul class="ul-demo">
        <li>使用 <code>ValidateForm</code> 表单组件,通过设置模型属性的 <code>FileValidation</code> 标签设置自定义验证,支持文件 <b>扩展名</b> <b>大小</b> 验证,本例中设置扩展名为 <code>.png .jpg .jpeg</code>,文件大小限制为 <code>50K</code></li>
        <li>选择文件后并未开始上传文件,点击 <code>提交</code> 按钮数据验证合法后,再 <code>OnSubmit</code> 回调委托中进行上传文件操作,注意 <b>Picture</b> 属性类型为 <code>IBrowserFile</code></li>
    </ul>
    <ValidateForm Model="Foo" OnValidSubmit="OnSubmit">
        <div class="row g-3">
            <div class="col-12">
                <BootstrapInput @bind-Value="@Foo.Name" />
            </div>
            <div class="col-12">
                <InputUpload @bind-Value="@Foo.Picture" />
            </div>
            <div class="col-12">
                <Button ButtonType="@ButtonType.Submit" Text="提交"></Button>
            </div>
        </div>
    </ValidateForm>
</Block>

<Block Title="点击上传" Introduction="<code>ButtonUpload</code> 组件,经典款式,用户点击按钮弹出文件选择框。">
    <div class="row g-3">
        <div class="col-12 col-sm-6">
            <p>点击 <code>浏览按钮</code> 选择文件上传,本例中设置 <code>IsMultiple=true</code> 可多选文件进行上传</p>
            <ButtonUpload TValue="string" IsMultiple="true" ShowProgress="true" OnChange="@OnClickToUpload" OnDelete="@(fileName => Task.FromResult(true))"></ButtonUpload>
        </div>
    </div>
    <p class="mt-3">设置 <code>IsSingle</code> 时,仅可以上传一张图片或者文件</p>
    <ButtonUpload TValue="string" IsSingle="true" OnChange="@OnClickToUpload" OnDelete="@(fileName => Task.FromResult(true))" class="mt-3"></ButtonUpload>
</Block>

<Block Title="已上传文件列表" Introduction="使用 <code>DefaultFileList</code> 设置已上传的内容">
    <div class="row g-3">
        <div class="col-12 col-sm-6">
            <ButtonUpload TValue="string" OnDelete="@(fileName => Task.FromResult(true))" DefaultFileList="@DefaultFormatFileList"></ButtonUpload>
        </div>
    </div>
</Block>

<Block Title="上传文件夹" Introduction="使用 <code>DefaultFileList</code> 设置已上传的内容">
    <div class="row g-3">
        <div class="col-12 col-sm-6">
            <ButtonUpload TValue="string" IsDirectory="true" OnChange="@OnUploadFolder" OnDelete="@(fileName => Task.FromResult(true))"></ButtonUpload>
        </div>
    </div>
</Block>

<Block Title="用户头像上传" Introduction="<code>AvatarUpload</code> 组件,使用 <code>OnChange</code> 限制用户上传的图片格式和大小。本例中仅允许上传 <code>jpg/png/bmp/jpeg/gif</code> 五种图片格式">
    <div class="row g-3">
        <div class="col-12">
            <p>卡片形式头像框</p>
            <AvatarUpload TValue="string" Accept="image/*" OnChange="@OnAvatarUpload" OnDelete="@(fileName => Task.FromResult(true))"></AvatarUpload>
        </div>
        <div class="col-12">
            <p>圆形头像框</p>
            <AvatarUpload TValue="string" Accept="image/*" ShowProgress="true" IsCircle="true" OnChange="@OnAvatarUpload" OnDelete="@(fileName => Task.FromResult(true))"></AvatarUpload>
        </div>
        <div class="col-12">
            <p>设置 <code>IsSingle</code> 时,仅可以上传一张图片或者文件</p>
            <AvatarUpload TValue="string" IsSingle="true" OnChange="@OnAvatarUpload" OnDelete="@(fileName => Task.FromResult(true))"></AvatarUpload>
            <p>
                <div>组件提供了 <code>Accept</code> 属性用于设置上传文件过滤功能,本例中圆形头像框接受 GIF 和 JPEG 两种图像,设置 <code>Accept="image/gif, image/jpeg"</code>,如果不限制图像的格式,可以写为:<code>Accept="image/*"</code>,该属性并不安全还是应该是使用 <b>服务器端验证</b> 进行文件格式验证</div>
            </p>
            <p>相关文档:<a href="https://www.runoob.com/tags/att-input-accept.html" target="_blank">[Accept 属性详解]</a> <a href="http://www.iana.org/assignments/media-types/media-types.xhtml" target="_blank">[Media Types 详细列表]</a></p>
            <AvatarUpload TValue="string" Accept="image/gif, image/jpeg" IsSingle="true" OnChange="@OnAvatarUpload" OnDelete="@(fileName => Task.FromResult(true))"></AvatarUpload>
        </div>
        <div class="col-12">
            <p>通过 <code>DefaultFileList</code> 属性设置预览地址 <code>PrevUrl</code> 即可</p>
            <AvatarUpload TValue="string" Accept="image/gif, image/jpeg" IsSingle="true" DefaultFileList="@PreviewFileList"
                          OnChange="@OnAvatarUpload" OnDelete="@(fileName => Task.FromResult(true))" />
        </div>
        <div class="col-12">
            <p>验证表单内使用头像框示例</p>
            <ValidateForm Model="Foo" OnValidSubmit="OnAvatarValidSubmit">
                <div class="row g-3">
                    <div class="col-12">
                        <BootstrapInput @bind-Value="@Foo.Name" />
                    </div>
                    <div class="col-12">
                        <AvatarUpload @bind-Value="@Foo.Picture" IsSingle="true" />
                    </div>
                    <div class="col-12">
                        <Button ButtonType="@ButtonType.Submit" Text="提交"></Button>
                    </div>
                </div>
            </ValidateForm>
        </div>
    </div>
    <BlockLogger @ref="AvatarTrace" class="mt-3" />
</Block>

<Block Title="预览卡片式" Introduction="<code>CardUpload</code> 组件,呈现为卡片式带预览模式">
    <p>
        <div><b>SSR 模式</b></div>
        <div><code>Server Side</code> 模式中可以使用 <code>IWebHostEnvironment</code> 注入服务获取到 <code>wwwwroot</code> 目录,保存文件到 <code>images\uploader</code> 中,此功能无需 <b>MVC</b> 的控制器辅助进行文件的保存,直接调用 <code>SaveToFile</code> 方法即可</div>

        <div><b>Wasm 模式</b></div>
        <div><code>wasm</code> 模式中无法使用 <code>IWebHostEnvironment</code> 需要调用 <code>webapi</code> 接口等形式将文件保存到服务器端</div>
        <div>有兴趣的同学可以通过开源仓库中的 <code>wiki</code> 文档中相关资源查看关于 <code>Upload</code> 组件的相关知识技巧 <a href="@SiteOptions.Value.VideoLibUrl" target="_blank">[传送门]</a></div>
        <div>本例中通过服务器端验证当文件大小超过 <code>200MB</code> 时,提示文件太大提示信息</div>
    </p>
    <div class="row g-3">
        <div class="col-12">
            <p>本例中设置 <code>ShowProgress=true</code> 显示上传进度条</p>
            <CardUpload TValue="string" ShowProgress="true" OnChange="@OnCardUpload" OnDelete="@(fileName => Task.FromResult(true))"></CardUpload>
        </div>
        <div class="col-12">
            <p>设置 <code>IsSingle</code> 时,仅可以上传一张图片或者文件</p>
            <CardUpload TValue="string" IsSingle="true" OnChange="@OnCardUpload" OnDelete="@(fileName => Task.FromResult(true))"></CardUpload>
        </div>
    </div>
</Block>

<Block Title="文件图标" Introduction="不同文件格式显示的图标不同">
    <CardUpload TValue="string" DefaultFileList="@DefaultFormatFileList" OnChange="@OnCardUpload" OnDelete="@(fileName => Task.FromResult(true))"></CardUpload>
</Block>

<Toast />

<AttributeTable Items="@GetInputAttributes()" Title="InputUpload" />

<AttributeTable Items="@GetButtonAttributes()" Title="ButtonUpload/CardUpload" />

<AttributeTable Items="@GetAvatarAttributes()" Title="AvatarUpload" />
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// 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 BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using BootstrapBlazor.Shared.Pages.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace BootstrapBlazor.Shared.Pages
{
    /// <summary>
    /// 
    /// </summary>
    public sealed partial class Uploads : IDisposable
    {
        private static readonly Random random = new();

        [Inject]
        [NotNull]
        private ToastService? ToastService { get; set; }

        [Inject]
        [NotNull]
        private IOptions<WebsiteOptions>? SiteOptions { get; set; }

        private List<UploadFile> PreviewFileList { get; } = new(new[] { new UploadFile { PrevUrl = "_content/BootstrapBlazor.Shared/images/Argo.png" } });

        private BlockLogger? Trace { get; set; }

        private List<UploadFile> DefaultFormatFileList { get; } = new List<UploadFile>()
        {
            new UploadFile { FileName = "Test.xls" },
            new UploadFile { FileName = "Test.doc" },
            new UploadFile { FileName = "Test.ppt" },
            new UploadFile { FileName = "Test.mp3" },
            new UploadFile { FileName = "Test.mp4" },
            new UploadFile { FileName = "Test.pdf" },
            new UploadFile { FileName = "Test.cs" },
            new UploadFile { FileName = "Test.zip" },
            new UploadFile { FileName = "Test.txt" },
            new UploadFile { FileName = "Test.dat" }
        };

        private Task OnFileChange(UploadFile file)
        {
            // 未真正保存文件
            // file.SaveToFile()
            Trace?.Log($"{file.File!.Name} 上传成功");
            return Task.FromResult("");
        }

        private async Task OnClickToUpload(UploadFile file)
        {
            // 示例代码,模拟 80% 几率保存成功
            var error = random.Next(1, 100) > 80;
            if (error)
            {
                file.Code = 1;
                file.Error = "模拟上传失败";
            }
            else
            {
                await SaveToFile(file);
            }
        }

        private CancellationTokenSource? UploadFolderToken { get; set; }
        private async Task OnUploadFolder(UploadFile file)
        {
            // 上传文件夹时会多次回调此方法
            await SaveToFile(file);
        }

        private CancellationTokenSource? ReadAvatarToken { get; set; }
        private async Task OnAvatarUpload(UploadFile file)
        {
            // 示例代码,使用 base64 格式
            if (file != null && file.File != null)
            {
                var format = file.File.ContentType;
                if (CheckValidAvatarFormat(format))
                {
                    ReadAvatarToken ??= new CancellationTokenSource();
                    if (ReadAvatarToken.IsCancellationRequested)
                    {
                        ReadAvatarToken.Dispose();
                        ReadAvatarToken = new CancellationTokenSource();
                    }

                    await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, ReadAvatarToken.Token);
                }
                else
                {
                    file.Code = 1;
                    file.Error = "文件格式不正确";
                }

                if (file.Code != 0)
                {
                    await ToastService.Error("头像上传", $"{file.Error} {format}");
                }
            }
        }

        private CancellationTokenSource? ReadToken { get; set; }

        private static long MaxFileLength => 200 * 1024 * 1024;

        private async Task OnCardUpload(UploadFile file)
        {
            if (file != null && file.File != null)
            {
                // 服务器端验证当文件大于 2MB 时提示文件太大信息
                if (file.Size > MaxFileLength)
                {
                    await ToastService.Information("上传文件", $"文件大小超过 200MB");
                    file.Code = 1;
                    file.Error = "文件大小超过 200MB";
                }
                else
                {
                    await SaveToFile(file);
                }
            }
        }

        private async Task<bool> SaveToFile(UploadFile file)
        {
            // Server Side 使用
            // Web Assembly 模式下必须使用 webapi 方式去保存文件到服务器或者数据库中
            // 生成写入文件名称
            var ret = false;
            if (!string.IsNullOrEmpty(SiteOptions.Value.WebRootPath))
            {
                var uploaderFolder = Path.Combine(SiteOptions.Value.WebRootPath, $"images{Path.DirectorySeparatorChar}uploader");
                file.FileName = $"{Path.GetFileNameWithoutExtension(file.OriginFileName)}-{DateTimeOffset.Now:yyyyMMddHHmmss}{Path.GetExtension(file.OriginFileName)}";
                var fileName = Path.Combine(uploaderFolder, file.FileName);

                ReadToken ??= new CancellationTokenSource();
                ret = await file.SaveToFile(fileName, MaxFileLength, ReadToken.Token);

                if (ret)
                {
                    // 保存成功
                    file.PrevUrl = $"images/uploader/{file.FileName}";
                }
                else
                {
                    var errorMessage = $"保存文件失败 {file.OriginFileName}";
                    file.Code = 1;
                    file.Error = errorMessage;
                    await ToastService.Error("上传文件", errorMessage);
                }
            }
            else
            {
                file.Code = 1;
                file.Error = "Wasm 模式未实现保存代码";
                await ToastService.Information("保存文件", "当前模式为 WebAssembly 模式,请调用 Webapi 模式保存文件到服务器端或数据库中");
            }
            return ret;
        }

        private static bool CheckValidAvatarFormat(string format)
        {
            return "jpg;png;bmp;gif;jpeg".Split(';').Any(f => format.Contains(f, StringComparison.OrdinalIgnoreCase));
        }

        private Task<bool> OnFileDelete(UploadFile item)
        {
            Trace?.Log($"{item.OriginFileName} 成功移除");
            return Task.FromResult(true);
        }

        [NotNull]
        private Person? Foo { get; set; } = new Person();

        private static Task OnSubmit(EditContext context)
        {
            return Task.CompletedTask;
        }

        [NotNull]
        private BlockLogger? AvatarTrace { get; set; }

        private Task OnAvatarValidSubmit(EditContext context)
        {
            AvatarTrace.Log(Foo.Picture?.Name ?? "");
            return Task.CompletedTask;
        }

        private class Person
        {
            [Required]
            [StringLength(20, MinimumLength = 2)]
            public string Name { get; set; } = "Blazor";

            [Required]
            [FileValidation(Extensions = new string[] { ".png", ".jpg", ".jpeg" }, FileSize = 50 * 1024)]
            public IBrowserFile? Picture { get; set; }
        }

        /// <summary>
        /// 获得属性方法
        /// </summary>
        /// <returns></returns>
        private static IEnumerable<AttributeItem> GetInputAttributes() => new AttributeItem[]
        {
            new AttributeItem() {
                Name = "ShowDeleteButton",
                Description = "是否显示删除按钮",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "IsDisabled",
                Description = "是否禁用",
                Type = "boolean",
                ValueList = "true / false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "PlaceHolder",
                Description = "占位字符串",
                Type = "string",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "Accept",
                Description = "上传接收的文件格式",
                Type = "string",
                ValueList = " — ",
                DefaultValue = " - "
            },
            new AttributeItem() {
                Name = "BrowserButtonClass",
                Description = "上传按钮样式",
                Type = "string",
                ValueList = " — ",
                DefaultValue = "btn-primary"
            },
            new AttributeItem() {
                Name = "BrowserButtonIcon",
                Description = "浏览按钮图标",
                Type = "string",
                ValueList = " — ",
                DefaultValue = "fa fa-folder-open-o"
            },
            new AttributeItem() {
                Name = "BrowserButtonText",
                Description = "浏览按钮显示文字",
                Type = "string",
                ValueList = " — ",
                DefaultValue = ""
            },
            new AttributeItem() {
                Name = "DeleteButtonClass",
                Description = "删除按钮样式",
                Type = "string",
                ValueList = " — ",
                DefaultValue = "btn-danger"
            },
            new AttributeItem() {
                Name = "DeleteButtonIcon",
                Description = "删除按钮图标",
                Type = "string",
                ValueList = " — ",
                DefaultValue = "fa fa-trash-o"
            },
            new AttributeItem() {
                Name = "DeleteButtonText",
                Description = "删除按钮文字",
                Type = "string",
                ValueList = " — ",
                DefaultValue = "删除"
            },
            new AttributeItem() {
                Name = "OnDelete",
                Description = "点击删除按钮时回调此方法",
                Type = "Func<string, Task<bool>>",
                ValueList = " — ",
                DefaultValue = " - "
            },
            new AttributeItem() {
                Name = "OnChange",
                Description = "点击浏览按钮时回调此方法",
                Type = "Func<UploadFile, Task>",
                ValueList = " — ",
                DefaultValue = " - "
            },
        };

        private static IEnumerable<AttributeItem> GetButtonAttributes() => new AttributeItem[]
        {
            new AttributeItem() {
                Name = "IsDirectory",
                Description = "是否上传整个目录",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "IsMultiple",
                Description = "是否允许多文件上传",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "IsSingle",
                Description = "是否仅上传一次",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "ShowProgress",
                Description = "是否显示上传进度",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "Accept",
                Description = "上传接收的文件格式",
                Type = "string",
                ValueList = " — ",
                DefaultValue = " - "
            },
            new AttributeItem() {
                Name = "BrowserButtonClass",
                Description = "上传按钮样式",
                Type = "string",
                ValueList = " — ",
                DefaultValue = "btn-primary"
            },
            new AttributeItem() {
                Name = "BrowserButtonIcon",
                Description = "浏览按钮图标",
                Type = "string",
                ValueList = " — ",
                DefaultValue = "fa fa-folder-open-o"
            },
            new AttributeItem() {
                Name = "BrowserButtonText",
                Description = "浏览按钮显示文字",
                Type = "string",
                ValueList = " — ",
                DefaultValue = ""
            },
            new AttributeItem() {
                Name = "DefaultFileList",
                Description = "已上传文件集合",
                Type = "List<UploadFile>",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "OnGetFileFormat",
                Description = "设置文件格式图标回调委托",
                Type = "Func<string, string>",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "OnDelete",
                Description = "点击删除按钮时回调此方法",
                Type = "Func<string, Task<bool>>",
                ValueList = " — ",
                DefaultValue = " - "
            },
            new AttributeItem() {
                Name = "OnChange",
                Description = "点击浏览按钮时回调此方法",
                Type = "Func<UploadFile, Task>",
                ValueList = " — ",
                DefaultValue = " - "
            },
        };

        private static IEnumerable<AttributeItem> GetAvatarAttributes() => new AttributeItem[]
        {
            new AttributeItem() {
                Name = "Width",
                Description = "预览框宽度",
                Type = "int",
                ValueList = " — ",
                DefaultValue = "0"
            },
            new AttributeItem() {
                Name = "Height",
                Description = "预览框高度",
                Type = "int",
                ValueList = "—",
                DefaultValue = "0"
            },
            new AttributeItem() {
                Name = "IsCircle",
                Description = "是否为圆形头像模式",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "IsSingle",
                Description = "是否仅上传一次",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "ShowProgress",
                Description = "是否显示上传进度",
                Type = "bool",
                ValueList = "true|false",
                DefaultValue = "false"
            },
            new AttributeItem() {
                Name = "Accept",
                Description = "上传接收的文件格式",
                Type = "string",
                ValueList = " — ",
                DefaultValue = " - "
            },
            new AttributeItem() {
                Name = "DefaultFileList",
                Description = "已上传文件集合",
                Type = "List<UploadFile>",
                ValueList = " — ",
                DefaultValue = " — "
            },
            new AttributeItem() {
                Name = "OnDelete",
                Description = "点击删除按钮时回调此方法",
                Type = "Func<string, Task<bool>>",
                ValueList = " — ",
                DefaultValue = " - "
            },
            new AttributeItem() {
                Name = "OnChange",
                Description = "点击浏览按钮时回调此方法",
                Type = "Func<UploadFile, Task>",
                ValueList = " — ",
                DefaultValue = " - "
            },
        };

        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            UploadFolderToken?.Dispose();
            ReadAvatarToken?.Cancel();
            ReadToken?.Cancel();
            GC.SuppressFinalize(this);
        }
    }
}

B 站相关视频链接

[传送门]

交流群

QQ Group:BootstrapAdmin & Blazor 795206915( Full) 675147445 Welcome to join the group discussion
Themes
Bootstrap
Ant Design (完善中)
Bluma (完善中)
LayUI (完善中)
Motronic (已集成)
An error has occurred. This application may no longer respond until reloaded. Reload