feat(Upload): use JavaScript isolation (#1189)

* feat: 增加更新预览集合方法

* feat: upload 组件使用脚本隔离

* feat: 增加 ShowZoomButton 参数

* test: 更新单元测试

* test: 更新单元测试
This commit is contained in:
Argo Zhang 2023-05-02 09:23:43 +08:00 committed by GitHub
parent 42c8523550
commit 26964d6041
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 123 additions and 93 deletions

View File

@ -16,7 +16,7 @@
{
<img alt="prevUrl" src="@item.PrevUrl" />
}
else if(IconTemplate != null)
else if (IconTemplate != null)
{
@IconTemplate(item)
}
@ -28,12 +28,15 @@
<div class="upload-item-size"><span>@item.GetFileName()</span> (@item.Size.ToFileSizeString())</div>
<div class="upload-item-actions">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-secondary btn-zoom" disabled="@GetDiabledString(item)" @onclick="() => OnClickZoom(item)" aria-label="zoom">
<i class="@ZoomIcon"></i>
</button>
@if(ShowDownloadButton)
@if (ShowZoomButton)
{
<button type="button" class="btn btn-sm btn-secondary" disabled="@GetDiabledString(item)" @onclick="() => OnClickDownload(item)" aria-label="download">
<button type="button" class="btn btn-sm btn-secondary btn-zoom" disabled="@GetDiabledString(item)" @onclick="() => OnClickZoom(item)" aria-label="zoom">
<i class="@ZoomIcon"></i>
</button>
}
@if (ShowDownloadButton)
{
<button type="button" class="btn btn-sm btn-secondary btn-download" disabled="@GetDiabledString(item)" @onclick="() => OnClickDownload(item)" aria-label="download">
<i class="@DownloadIcon"></i>
</button>
}

View File

@ -73,6 +73,12 @@ public partial class CardUpload<TValue>
[Parameter]
public string? ZoomIcon { get; set; }
/// <summary>
/// 获得/设置 是否显示放大按钮 默认 true
/// </summary>
[Parameter]
public bool ShowZoomButton { get; set; } = true;
[Inject]
[NotNull]
private IIconTheme? IconTheme { get; set; }

View File

@ -9,7 +9,7 @@ namespace BootstrapBlazor.Components;
/// <summary>
/// Upload 组件基类
/// </summary>
[JSModuleAutoLoader("upload", ModuleName = "Upload")]
[JSModuleAutoLoader(ModuleName = "upload")]
public abstract class UploadBase<TValue> : ValidateBase<TValue>, IUpload
{
/// <summary>

View File

@ -1,93 +1,81 @@
import Data from "./data.js"
import EventHandler from "./base/event-handler.js"
import BlazorComponent from "./base/blazor-component.js"
import EventHandler from "./event-handler.js"
import Viewer from "./viewer.js"
export class Upload extends BlazorComponent {
static get Default() {
return {
browserClass: '.btn-browser'
export function init(id) {
const el = document.getElementById(id)
if (el === null) {
return
}
const preventHandler = e => e.preventDefault()
const upload = { el, preventHandler }
Data.set(id, upload)
const inputFile = el.querySelector('[type="file"]')
EventHandler.on(el, 'click', '.btn-browser', () => {
inputFile.click()
})
//阻止浏览器默认行为
EventHandler.on(document, "dragleave", preventHandler)
EventHandler.on(document, 'drop', preventHandler)
EventHandler.on(document, 'dragenter', preventHandler)
EventHandler.on(document, 'dragover', preventHandler)
EventHandler.on(el, 'drop', e => {
try {
//获取文件对象
const fileList = e.dataTransfer.files
//检测是否是拖拽文件到页面的操作
if (fileList.length === 0) {
return false
}
inputFile.files = e.dataTransfer.files
const event = new Event('change', { bubbles: true })
inputFile.dispatchEvent(event)
} catch (e) {
console.error(e)
}
}
})
_init() {
this._inputFile = this._element.querySelector('[type="file"]')
this._setListeners()
}
EventHandler.on(el, 'paste', e => {
inputFile.files = e.clipboardData.files
const event = new Event('change', { bubbles: true })
inputFile.dispatchEvent(event)
})
_setListeners() {
EventHandler.on(this._element, 'click', this._config.browserClass, () => {
this._inputFile.click()
})
//阻止浏览器默认行为
EventHandler.on(document, "dragleave", e => {
e.preventDefault()
})
EventHandler.on(document, 'drop', e => {
e.preventDefault()
})
EventHandler.on(document, 'dragenter', e => {
e.preventDefault()
})
EventHandler.on(document, 'dragover', e => {
e.preventDefault()
})
EventHandler.on(this._element, 'drop', e => {
try {
//获取文件对象
const fileList = e.dataTransfer.files
//检测是否是拖拽文件到页面的操作
if (fileList.length === 0) {
return false;
}
this._inputFile.files = e.dataTransfer.files;
const event = new Event('change', { bubbles: true });
this._inputFile.dispatchEvent(event);
} catch (e) {
console.error(e);
}
})
EventHandler.on(this._element, 'paste', e => {
this._inputFile.files = e.clipboardData.files;
const event = new Event('change', { bubbles: true });
this._inputFile.dispatchEvent(event);
});
EventHandler.on(this._element, 'click', '.btn-zoom', e => {
if (!this._previewer) {
this._previewer = Data.get(this._config.previewerId)
}
const button = e.delegateTarget
const buttons = [...this._element.querySelectorAll('.btn-zoom')]
this._previewer.viewer.show(buttons.indexOf(button))
})
}
_execute(args) {
const tooltipId = args[0]
const method = args[1]
if (method === 'disposeTooltip' && tooltipId) {
const element = document.getElementById(tooltipId)
if (element) {
const tooltip = bootstrap.Tooltip.getInstance(element)
if (tooltip) {
tooltip.dispose()
}
}
EventHandler.on(el, 'click', '.btn-zoom', e => {
if (!upload.viewer) {
const previewId = el.getAttribute('data-bb-previewer-id')
const viewEl = document.getElementById(previewId)
upload.viewer = Viewer.init(viewEl, [])
upload.viewEl = viewEl
}
}
const button = e.delegateTarget
const buttons = [...el.querySelectorAll('.btn-zoom')]
upload.viewer.updatePrevList([...el.querySelectorAll('.upload-body img')].map(v => v.src))
upload.viewer.show(buttons.indexOf(button))
})
}
_dispose() {
EventHandler.off(this._element, 'click', this._config.browserClass)
EventHandler.off(document, 'dragleave');
EventHandler.off(document, 'drop');
EventHandler.off(document, 'dragenter');
EventHandler.off(document, 'dragover');
EventHandler.off(this._element, 'drop');
EventHandler.off(this._element, 'paste');
export function dispose(id) {
const upload = Data.get(id)
Data.remove(id)
const el = upload.el
const preventHandler = upload.preventHandler
if (upload) {
if (upload.viewer) {
upload.viewer.dispose(upload.viewEl)
}
EventHandler.off(el, 'click')
EventHandler.off(el, 'drop')
EventHandler.off(el, 'paste')
EventHandler.off(document, 'dragleave', preventHandler)
EventHandler.off(document, 'drop', preventHandler)
EventHandler.off(document, 'dragenter', preventHandler)
EventHandler.off(document, 'dragover', preventHandler)
}
}

View File

@ -36,6 +36,10 @@ export default {
viewer.el.classList.add('show')
}
viewer.updatePrevList = prevList => {
viewer.prevList = prevList
}
viewer.resetImage = () => {
viewer.prevImg.classList.add('transition-none')
viewer.prevImg.style.transform = 'scale(1) rotate(0deg)'

View File

@ -755,11 +755,40 @@ public class UploadTest : BootstrapBlazorTestBase
});
});
var button = cut.FindAll(".btn-secondary");
await cut.InvokeAsync(() => button[1].Click());
var button = cut.Find(".btn-download");
await cut.InvokeAsync(() => button.Click());
Assert.True(clicked);
}
[Fact]
public async Task CardUpload_ShowZoom()
{
var clicked = false;
var cut = Context.RenderComponent<CardUpload<string>>(pb =>
{
pb.Add(a => a.ShowZoomButton, true);
pb.Add(a => a.OnZoomAsync, file =>
{
clicked = true;
return Task.CompletedTask;
});
pb.Add(a => a.DefaultFileList, new List<UploadFile>()
{
new UploadFile() { FileName = "Test-File1.text" }
});
});
var button = cut.Find(".btn-zoom");
await cut.InvokeAsync(() => button.Click());
Assert.True(clicked);
cut.SetParametersAndRender(pb =>
{
pb.Add(a => a.ShowZoomButton, false);
});
cut.DoesNotContain("btn-zoom");
}
[Fact]
public void CardUpload_ValidateForm_Ok()
{