From 308e728c6f497db4668c2588e8bdae198b0f0ffd Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 11:03:46 +0800 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20readFileToBl?= =?UTF-8?q?obAsync=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/wwwroot/modules/utility.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/BootstrapBlazor/wwwroot/modules/utility.js b/src/BootstrapBlazor/wwwroot/modules/utility.js index b5ea69e7025..d0bbb744e39 100644 --- a/src/BootstrapBlazor/wwwroot/modules/utility.js +++ b/src/BootstrapBlazor/wwwroot/modules/utility.js @@ -886,6 +886,23 @@ export function drawImage(canvas, image, offsetWidth, offsetHeight) { context.drawImage(image, 0, 0, offsetWidth, offsetHeight); } +export function readFileToBlobAsync(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = () => { + const blob = new Blob([reader.result], { type: file.type }); + resolve(blob); + }; + + reader.onerror = (error) => { + reject(error); + }; + + reader.readAsArrayBuffer(file); + }); +} + export { autoAdd, autoRemove, From 1d92a3de59d4022ceba193cff245ceb79366171a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 11:14:34 +0800 Subject: [PATCH 02/10] =?UTF-8?q?chore:=20=E6=96=B9=E6=B3=95=E9=87=8D?= =?UTF-8?q?=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/wwwroot/modules/utility.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/wwwroot/modules/utility.js b/src/BootstrapBlazor/wwwroot/modules/utility.js index d0bbb744e39..b6793d586a0 100644 --- a/src/BootstrapBlazor/wwwroot/modules/utility.js +++ b/src/BootstrapBlazor/wwwroot/modules/utility.js @@ -886,7 +886,7 @@ export function drawImage(canvas, image, offsetWidth, offsetHeight) { context.drawImage(image, 0, 0, offsetWidth, offsetHeight); } -export function readFileToBlobAsync(file) { +export function readFileAsync(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); From 64e52ebf4acc242280119339dd7441c0b774b374 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 11:36:44 +0800 Subject: [PATCH 03/10] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20getPreviewUr?= =?UTF-8?q?l=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/wwwroot/modules/upload.js | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/wwwroot/modules/upload.js b/src/BootstrapBlazor/wwwroot/modules/upload.js index 28334a53267..b646000c56d 100644 --- a/src/BootstrapBlazor/wwwroot/modules/upload.js +++ b/src/BootstrapBlazor/wwwroot/modules/upload.js @@ -1,20 +1,24 @@ import Data from "./data.js" import EventHandler from "./event-handler.js" +import { readFileAsync } from "./utility.js" export function init(id) { const el = document.getElementById(id) if (el === null) { return } - const preventHandler = e => e.preventDefault() + const preventHandler = e => e.preventDefault(); const body = el.querySelector('.upload-drop-body'); - const upload = { el, body, preventHandler } + const inputFile = el.querySelector('[type="file"]'); + const upload = { el, body, preventHandler, inputFile }; Data.set(id, upload) - const inputFile = el.querySelector('[type="file"]') EventHandler.on(el, 'click', '.btn-browser', () => { inputFile.click() }) + EventHandler.on(inputFile, 'change', e => { + upload.files = e.delegateTarget.files; + }); EventHandler.on(document, "dragleave", preventHandler) EventHandler.on(document, 'drop', preventHandler) @@ -79,12 +83,28 @@ export function init(id) { }) } +export async function getPreviewUrl(id, fileName) { + let url = ''; + const upload = Data.get(id); + const { files } = upload; + if (files) { + const file = [...files].find(v => v.name === fileName); + if (file) { + const data = await readFileAsync(file); + if (data) { + url = URL.createObjectURL(data); + } + } + } + return url; +} + export function dispose(id) { const upload = Data.get(id) Data.remove(id) if (upload) { - const { el, body, preventHandler } = upload; + const { el, body, preventHandler, inputFile } = upload; EventHandler.off(document, 'dragleave', preventHandler) EventHandler.off(document, 'drop', preventHandler) @@ -94,6 +114,7 @@ export function dispose(id) { EventHandler.off(el, 'click') EventHandler.off(el, 'drop') EventHandler.off(el, 'paste') + EventHandler.off(inputFile, 'change') EventHandler.off(body, 'dragleave') EventHandler.off(body, 'drop') EventHandler.off(body, 'dragenter') From 2c9c2be524dc7f117c43b31f13cac56920c71abd Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 11:36:56 +0800 Subject: [PATCH 04/10] =?UTF-8?q?refactor:=20=E6=94=B9=E7=94=A8=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E9=A2=84=E8=A7=88=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index 6c45f79c416..fdf93d1cea1 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -133,14 +133,9 @@ protected override void OnParametersSet() /// protected override async Task TriggerOnChanged(UploadFile file) { - if (OnChange == null) - { - await file.RequestBase64ImageFileAsync(allowExtensions: AllowExtensions); - } - else - { - await OnChange(file); - } + // 从客户端获得预览地址不使用 base64 编码 + file.PrevUrl = await InvokeAsync("getPreviewUrl", Id, file.OriginFileName); + await base.TriggerOnChanged(file); } private IReadOnlyCollection _results = []; From 186b9bfecf984e957dda17560aa3bc9dfe594e53 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 12:02:44 +0800 Subject: [PATCH 05/10] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E5=A4=B4?= =?UTF-8?q?=E5=83=8F=E4=B8=8A=E4=BC=A0=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/UploadAvatars.razor | 4 +-- .../Components/Samples/UploadAvatars.razor.cs | 33 +++---------------- src/BootstrapBlazor.Server/Locales/en-US.json | 1 + src/BootstrapBlazor.Server/Locales/zh-CN.json | 1 + 4 files changed, 8 insertions(+), 31 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor index c18a81a9598..d53e429e239 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor @@ -55,13 +55,13 @@ - + - +
diff --git a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs index bdef10c2e00..d3d4b8b0e37 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs @@ -37,39 +37,14 @@ protected override void OnInitialized() ]); } - private async Task OnChange(UploadFile file) + private Task OnAvatarValidSubmit(EditContext context) { - // 示例代码,使用 base64 格式 - if (file is { File: not null }) - { - var format = file.File.ContentType; - if (file.IsImage()) - { - _token ??= new CancellationTokenSource(); - if (_token.IsCancellationRequested) - { - _token.Dispose(); - _token = new CancellationTokenSource(); - } - - await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, null, _token.Token); - } - else - { - file.Code = 1; - file.Error = Localizer["UploadsFormatError"]; - } - - if (file.Code != 0) - { - await ToastService.Error(Localizer["UploadsAvatarMsg"], $"{file.Error} {format}"); - } - } + return ToastService.Success(Localizer["UploadsValidateFormTitle"], Localizer["UploadsValidateFormValidContent"]); } - private Task OnAvatarValidSubmit(EditContext context) + private Task OnAvatarInValidSubmit(EditContext context) { - return ToastService.Error(Localizer["UploadsValidateFormTitle"], Localizer["UploadsValidateFormValidContent"]); + return ToastService.Error(Localizer["UploadsValidateFormTitle"], Localizer["UploadsValidateFormInValidContent"]); } /// diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 65cd7bd79d6..ff88e9dae37 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -3481,6 +3481,7 @@ "UploadsBorderRadius": "Border radius", "UploadsValidateFormTitle": "ValidateForm", "UploadsValidateFormValidContent": "Saved successfully", + "UploadsValidateFormInValidContent": "Please correct it and submit the form again", "UploadsFormatError": "The file format is incorrect", "UploadsAvatarMsg": "Avatar upload" }, diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 4411ee902bb..211bd6fdbc7 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -3481,6 +3481,7 @@ "UploadsBorderRadius": "预览框圆角曲率", "UploadsValidateFormTitle": "表单应用", "UploadsValidateFormValidContent": "数据合规,保存成功", + "UploadsValidateFormInValidContent": "数据不合规,请更正后再提交表单", "UploadsFormatError": "文件格式不正确", "UploadsAvatarMsg": "头像上传" }, From 1b6a9fd179d9ea89d1fad7b553f94ca2cc65e65d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 12:13:53 +0800 Subject: [PATCH 06/10] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20CanPrevi?= =?UTF-8?q?ewCallback=20=E5=9B=9E=E8=B0=83=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/AvatarUpload.razor.cs | 11 ++++++++++- .../Extensions/UploadFileExtensions.cs | 8 ++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs index fdf93d1cea1..7aca5d0fa1f 100644 --- a/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs @@ -77,6 +77,12 @@ public partial class AvatarUpload [Parameter] public bool IsUploadButtonAtFirst { get; set; } + /// + /// 获得/设置 是否允许预览回调方法 默认 null + /// + [Parameter] + public Func? CanPreviewCallback { get; set; } + [Inject] [NotNull] private IIconTheme? IconTheme { get; set; } @@ -134,7 +140,10 @@ protected override void OnParametersSet() protected override async Task TriggerOnChanged(UploadFile file) { // 从客户端获得预览地址不使用 base64 编码 - file.PrevUrl = await InvokeAsync("getPreviewUrl", Id, file.OriginFileName); + if (file.IsImage(AllowExtensions, CanPreviewCallback)) + { + file.PrevUrl = await InvokeAsync("getPreviewUrl", Id, file.OriginFileName); + } await base.TriggerOnChanged(file); } diff --git a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs index 9897efed35d..94f4eab7f4f 100644 --- a/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs +++ b/src/BootstrapBlazor/Extensions/UploadFileExtensions.cs @@ -194,14 +194,14 @@ public static async Task SaveToFileAsync(this UploadFile upload, string fi /// /// /// - /// + /// /// - public static bool IsImage(this UploadFile item, List? allowExtensions = null, Func? _callback = null) + public static bool IsImage(this UploadFile item, List? allowExtensions = null, Func? callback = null) { bool ret; - if (_callback != null) + if (callback != null) { - ret = _callback(item); + ret = callback(item); } else if (item.File != null) { From d8b8453d6a20ecb7df73deb72dae3a733fb1fc65 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 12:17:09 +0800 Subject: [PATCH 07/10] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E9=A2=84=E8=A7=88=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Upload/CardUpload.razor.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs index 989082efb76..c5363e0c09b 100644 --- a/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs +++ b/src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs @@ -133,6 +133,21 @@ protected override void OnParametersSet() RemoveIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadRemoveIcon); } + /// + /// + /// + /// + /// + protected override async Task TriggerOnChanged(UploadFile file) + { + // 从客户端获得预览地址不使用 base64 编码 + if (file.IsImage(AllowExtensions, CanPreviewCallback)) + { + file.PrevUrl = await InvokeAsync("getPreviewUrl", Id, file.OriginFileName); + } + await base.TriggerOnChanged(file); + } + private async Task OnCardFileDelete(UploadFile item) { await OnFileDelete(item); From 74053c091f26f9af004dbf6f7874b3593035eefc Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 12:40:25 +0800 Subject: [PATCH 08/10] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=80=BC=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/wwwroot/modules/utility.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/BootstrapBlazor/wwwroot/modules/utility.js b/src/BootstrapBlazor/wwwroot/modules/utility.js index b6793d586a0..aecd390294d 100644 --- a/src/BootstrapBlazor/wwwroot/modules/utility.js +++ b/src/BootstrapBlazor/wwwroot/modules/utility.js @@ -886,6 +886,10 @@ export function drawImage(canvas, image, offsetWidth, offsetHeight) { context.drawImage(image, 0, 0, offsetWidth, offsetHeight); } +/** + * @param {File} file + * @returns {Blob} + */ export function readFileAsync(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); From 4ade24e38d8a1d67e58a67e49a92f65a0a91b7e7 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 12:42:10 +0800 Subject: [PATCH 09/10] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/UploadAvatarTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/UnitTest/Components/UploadAvatarTest.cs b/test/UnitTest/Components/UploadAvatarTest.cs index 6afe95d8472..a456bae0c5e 100644 --- a/test/UnitTest/Components/UploadAvatarTest.cs +++ b/test/UnitTest/Components/UploadAvatarTest.cs @@ -17,6 +17,7 @@ public async Task AvatarUpload_Ok() UploadFile? uploadFile = null; var cut = Context.RenderComponent>(pb => { + pb.Add(a => a.CanPreviewCallback, null); pb.Add(a => a.IsMultiple, true); pb.Add(a => a.OnChange, file => { From 5f86566cf67bc838ba5a2ecc3d6083e1c68dfea6 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 5 Jun 2025 12:44:02 +0800 Subject: [PATCH 10/10] chore: bump version 9.7.1-beta05 --- src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 8b68a932561..ac8e7c9c6ae 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 9.7.1-beta04 + 9.7.1-beta05