Skip to content

Commit 16cc7d4

Browse files
authored
feat(Upload): use local preview instead of base64 format (#6157)
* feat: 增加 readFileToBlobAsync 方法 * chore: 方法重命名 * feat: 增加 getPreviewUrl 方法 * refactor: 改用客户端预览方法 * doc: 更新头像上传示例 * refactor: 增加 CanPreviewCallback 回调方法 * refactor: 增加图片预览功能 * refactor: 增加返回值注释 * test: 更新单元测试 * chore: bump version 9.7.1-beta05
1 parent 7e580f9 commit 16cc7d4

11 files changed

Lines changed: 85 additions & 46 deletions

File tree

src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@
5555
<DemoBlock Title="@Localizer["AvatarUploadAcceptTitle"]"
5656
Introduction="@Localizer["AvatarUploadAcceptIntro"]"
5757
Name="Accept">
58-
<AvatarUpload TValue="string" Accept="image/*" OnChange="@OnChange"></AvatarUpload>
58+
<AvatarUpload TValue="string" Accept="image/*"></AvatarUpload>
5959
</DemoBlock>
6060

6161
<DemoBlock Title="@Localizer["AvatarUploadValidateTitle"]"
6262
Introduction="@Localizer["AvatarUploadValidateIntro"]"
6363
Name="ValidateForm">
64-
<ValidateForm Model="@_foo" OnValidSubmit="OnAvatarValidSubmit">
64+
<ValidateForm Model="@_foo" OnValidSubmit="OnAvatarValidSubmit" OnInValidSubmit="OnAvatarInValidSubmit">
6565
<div class="row g-3">
6666
<div class="col-12">
6767
<BootstrapInput @bind-Value="@_foo.Name"></BootstrapInput>

src/BootstrapBlazor.Server/Components/Samples/UploadAvatars.razor.cs

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,39 +37,14 @@ protected override void OnInitialized()
3737
]);
3838
}
3939

40-
private async Task OnChange(UploadFile file)
40+
private Task OnAvatarValidSubmit(EditContext context)
4141
{
42-
// 示例代码,使用 base64 格式
43-
if (file is { File: not null })
44-
{
45-
var format = file.File.ContentType;
46-
if (file.IsImage())
47-
{
48-
_token ??= new CancellationTokenSource();
49-
if (_token.IsCancellationRequested)
50-
{
51-
_token.Dispose();
52-
_token = new CancellationTokenSource();
53-
}
54-
55-
await file.RequestBase64ImageFileAsync(format, 640, 480, MaxFileLength, null, _token.Token);
56-
}
57-
else
58-
{
59-
file.Code = 1;
60-
file.Error = Localizer["UploadsFormatError"];
61-
}
62-
63-
if (file.Code != 0)
64-
{
65-
await ToastService.Error(Localizer["UploadsAvatarMsg"], $"{file.Error} {format}");
66-
}
67-
}
42+
return ToastService.Success(Localizer["UploadsValidateFormTitle"], Localizer["UploadsValidateFormValidContent"]);
6843
}
6944

70-
private Task OnAvatarValidSubmit(EditContext context)
45+
private Task OnAvatarInValidSubmit(EditContext context)
7146
{
72-
return ToastService.Error(Localizer["UploadsValidateFormTitle"], Localizer["UploadsValidateFormValidContent"]);
47+
return ToastService.Error(Localizer["UploadsValidateFormTitle"], Localizer["UploadsValidateFormInValidContent"]);
7348
}
7449

7550
/// <summary>

src/BootstrapBlazor.Server/Locales/en-US.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3481,6 +3481,7 @@
34813481
"UploadsBorderRadius": "Border radius",
34823482
"UploadsValidateFormTitle": "ValidateForm",
34833483
"UploadsValidateFormValidContent": "Saved successfully",
3484+
"UploadsValidateFormInValidContent": "Please correct it and submit the form again",
34843485
"UploadsFormatError": "The file format is incorrect",
34853486
"UploadsAvatarMsg": "Avatar upload"
34863487
},

src/BootstrapBlazor.Server/Locales/zh-CN.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3481,6 +3481,7 @@
34813481
"UploadsBorderRadius": "预览框圆角曲率",
34823482
"UploadsValidateFormTitle": "表单应用",
34833483
"UploadsValidateFormValidContent": "数据合规,保存成功",
3484+
"UploadsValidateFormInValidContent": "数据不合规,请更正后再提交表单",
34843485
"UploadsFormatError": "文件格式不正确",
34853486
"UploadsAvatarMsg": "头像上传"
34863487
},

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>9.7.1-beta04</Version>
4+
<Version>9.7.1-beta05</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/Upload/AvatarUpload.razor.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ public partial class AvatarUpload<TValue>
7777
[Parameter]
7878
public bool IsUploadButtonAtFirst { get; set; }
7979

80+
/// <summary>
81+
/// 获得/设置 是否允许预览回调方法 默认 null
82+
/// </summary>
83+
[Parameter]
84+
public Func<UploadFile, bool>? CanPreviewCallback { get; set; }
85+
8086
[Inject]
8187
[NotNull]
8288
private IIconTheme? IconTheme { get; set; }
@@ -133,14 +139,12 @@ protected override void OnParametersSet()
133139
/// <returns></returns>
134140
protected override async Task TriggerOnChanged(UploadFile file)
135141
{
136-
if (OnChange == null)
137-
{
138-
await file.RequestBase64ImageFileAsync(allowExtensions: AllowExtensions);
139-
}
140-
else
142+
// 从客户端获得预览地址不使用 base64 编码
143+
if (file.IsImage(AllowExtensions, CanPreviewCallback))
141144
{
142-
await OnChange(file);
145+
file.PrevUrl = await InvokeAsync<string?>("getPreviewUrl", Id, file.OriginFileName);
143146
}
147+
await base.TriggerOnChanged(file);
144148
}
145149

146150
private IReadOnlyCollection<ValidationResult> _results = [];

src/BootstrapBlazor/Components/Upload/CardUpload.razor.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,21 @@ protected override void OnParametersSet()
133133
RemoveIcon ??= IconTheme.GetIconByKey(ComponentIcons.CardUploadRemoveIcon);
134134
}
135135

136+
/// <summary>
137+
/// <inheritdoc/>
138+
/// </summary>
139+
/// <param name="file"></param>
140+
/// <returns></returns>
141+
protected override async Task TriggerOnChanged(UploadFile file)
142+
{
143+
// 从客户端获得预览地址不使用 base64 编码
144+
if (file.IsImage(AllowExtensions, CanPreviewCallback))
145+
{
146+
file.PrevUrl = await InvokeAsync<string?>("getPreviewUrl", Id, file.OriginFileName);
147+
}
148+
await base.TriggerOnChanged(file);
149+
}
150+
136151
private async Task OnCardFileDelete(UploadFile item)
137152
{
138153
await OnFileDelete(item);

src/BootstrapBlazor/Extensions/UploadFileExtensions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,14 @@ public static async Task<bool> SaveToFileAsync(this UploadFile upload, string fi
194194
/// </summary>
195195
/// <param name="item"></param>
196196
/// <param name="allowExtensions"></param>
197-
/// <param name="_callback"></param>
197+
/// <param name="callback"></param>
198198
/// <returns></returns>
199-
public static bool IsImage(this UploadFile item, List<string>? allowExtensions = null, Func<UploadFile, bool>? _callback = null)
199+
public static bool IsImage(this UploadFile item, List<string>? allowExtensions = null, Func<UploadFile, bool>? callback = null)
200200
{
201201
bool ret;
202-
if (_callback != null)
202+
if (callback != null)
203203
{
204-
ret = _callback(item);
204+
ret = callback(item);
205205
}
206206
else if (item.File != null)
207207
{

src/BootstrapBlazor/wwwroot/modules/upload.js

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import Data from "./data.js"
22
import EventHandler from "./event-handler.js"
3+
import { readFileAsync } from "./utility.js"
34

45
export function init(id) {
56
const el = document.getElementById(id)
67
if (el === null) {
78
return
89
}
9-
const preventHandler = e => e.preventDefault()
10+
const preventHandler = e => e.preventDefault();
1011
const body = el.querySelector('.upload-drop-body');
11-
const upload = { el, body, preventHandler }
12+
const inputFile = el.querySelector('[type="file"]');
13+
const upload = { el, body, preventHandler, inputFile };
1214
Data.set(id, upload)
1315

14-
const inputFile = el.querySelector('[type="file"]')
1516
EventHandler.on(el, 'click', '.btn-browser', () => {
1617
inputFile.click()
1718
})
19+
EventHandler.on(inputFile, 'change', e => {
20+
upload.files = e.delegateTarget.files;
21+
});
1822

1923
EventHandler.on(document, "dragleave", preventHandler)
2024
EventHandler.on(document, 'drop', preventHandler)
@@ -79,12 +83,28 @@ export function init(id) {
7983
})
8084
}
8185

86+
export async function getPreviewUrl(id, fileName) {
87+
let url = '';
88+
const upload = Data.get(id);
89+
const { files } = upload;
90+
if (files) {
91+
const file = [...files].find(v => v.name === fileName);
92+
if (file) {
93+
const data = await readFileAsync(file);
94+
if (data) {
95+
url = URL.createObjectURL(data);
96+
}
97+
}
98+
}
99+
return url;
100+
}
101+
82102
export function dispose(id) {
83103
const upload = Data.get(id)
84104
Data.remove(id)
85105

86106
if (upload) {
87-
const { el, body, preventHandler } = upload;
107+
const { el, body, preventHandler, inputFile } = upload;
88108

89109
EventHandler.off(document, 'dragleave', preventHandler)
90110
EventHandler.off(document, 'drop', preventHandler)
@@ -94,6 +114,7 @@ export function dispose(id) {
94114
EventHandler.off(el, 'click')
95115
EventHandler.off(el, 'drop')
96116
EventHandler.off(el, 'paste')
117+
EventHandler.off(inputFile, 'change')
97118
EventHandler.off(body, 'dragleave')
98119
EventHandler.off(body, 'drop')
99120
EventHandler.off(body, 'dragenter')

src/BootstrapBlazor/wwwroot/modules/utility.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,27 @@ export function drawImage(canvas, image, offsetWidth, offsetHeight) {
886886
context.drawImage(image, 0, 0, offsetWidth, offsetHeight);
887887
}
888888

889+
/**
890+
* @param {File} file
891+
* @returns {Blob}
892+
*/
893+
export function readFileAsync(file) {
894+
return new Promise((resolve, reject) => {
895+
const reader = new FileReader();
896+
897+
reader.onload = () => {
898+
const blob = new Blob([reader.result], { type: file.type });
899+
resolve(blob);
900+
};
901+
902+
reader.onerror = (error) => {
903+
reject(error);
904+
};
905+
906+
reader.readAsArrayBuffer(file);
907+
});
908+
}
909+
889910
export {
890911
autoAdd,
891912
autoRemove,

0 commit comments

Comments
 (0)