- A+
在很多上传文件的应用实例中, 都可以看到[拖放文件到此上传]这种骚功能 ,今天我们就来试试Blazor能不能完成这个想法.
原文链接:https://www.cnblogs.com/densen2014/p/16128246.html
简述HTML5拖放
拖放是HTML5标准的一部分,任何元素都能够拖放,也能够将本地的文件拖放到页面上。
设置元素可拖放
为了使元素可拖动,把 draggable 属性设置为 true
<img draggable="true" />
拖放事件
有7个拖放事件可以捕获,如下:
dragstart:开始拖元素触发
dragenter:元素拖进可drop元素(绑定drop事件的元素)时触发
dragover:当元素拖动到drop元素上时触发
drop:当元素放下到drop元素触发
dragleave :当元素离开drop元素时触发
drag:每次元素被拖动时会触发
dragend:放开拖动元素时触发
完成一次拖放的事件过程是: dragstart –> dragenter –> dragover –> drop –> dragend
浏览器支持
Edge、Firefox、Opera 12、Chrome 以及 Safari 5 支持拖放。
拖拽上传实现
1.新建工程n02drag,将项目添加到解决方案中
dotnet new blazorserver -o n02drag dotnet sln add n02drag/n02drag.csproj
2.在文件夹wwwroot/lib,添加drag子文件夹,新建app.js文件
先阻止页面默认的拖放行为,不然页面会被拖放的文件替换了。
//阻止浏览器默认行为 document.addEventListener( "dragleave", function(e) { e.preventDefault(); }, false); document.addEventListener( "drop", function(e) { e.preventDefault(); }, false); document.addEventListener( "dragenter", function(e) { e.preventDefault(); }, false); document.addEventListener( "dragover", function(e) { e.preventDefault(); }, false);
设置drop区域
当文件拖放到drop区域时,就能触发上传。
element.addEventListener("drop", function (e) { try { var 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) { wrapper.invokeMethodAsync('DropAlert', e); } }, false);
2.在文件Pages/Index.razor,添加上传组件
页面
@implements IAsyncDisposable @inject IJSRuntime JS <div @ref="UploadElement" style="padding: 20px; width: 200px; height: 200px; background-color: cornflowerblue; border: 2px dashed #0087F7; border-radius: 5px; "> <p>拖放上传文件</p> <InputFile OnChange="OnChange" class="form-control" multiple @ref="inputFile"/> </div> <pre> <code> @uploadstatus </code> </pre>
代码
- InputFile 开启 multiple ,接受多文件上传
- 使用JS隔离技术
- Dispose处理回收
@code{ [Inject] protected Microsoft.AspNetCore.Hosting.IWebHostEnvironment? HostEnvironment { get; set; } //获取IWebHostEnvironment protected ElementReference UploadElement { get; set; } protected InputFile? inputFile { get; set; } private DotNetObjectReference<Index>? wrapper; private IJSObjectReference? module; private IJSObjectReference? dropInstance; protected string UploadPath = ""; protected string? uploadstatus; long maxFileSize = 1024 * 1024 * 15; protected override void OnAfterRender(bool firstRender) { if (!firstRender) return; UploadPath = Path.Combine(HostEnvironment!.WebRootPath, "Upload"); //初始化上传路径 if (!Directory.Exists(UploadPath)) Directory.CreateDirectory(UploadPath); //不存在则新建目录 } protected async Task OnChange(InputFileChangeEventArgs e) { int i = 0; var selectedFiles = e.GetMultipleFiles(100); foreach (var item in selectedFiles) { i++; await OnSubmit(item); uploadstatus += Environment.NewLine + $"[{i}]: " + item.Name; } } protected async Task OnSubmit(IBrowserFile efile) { if (efile == null) return; var tempfilename = Path.Combine(UploadPath, efile.Name); await using FileStream fs = new(tempfilename, FileMode.Create); using var stream = efile.OpenReadStream(maxFileSize); await stream.CopyToAsync(fs); StateHasChanged(); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) return; module = await JS.InvokeAsync<IJSObjectReference>("import", "./lib/drag/app.js"); wrapper = DotNetObjectReference.Create(this); dropInstance = await module.InvokeAsync<IJSObjectReference>("init", wrapper , UploadElement, inputFile!.Element); } [JSInvokable] public void DropAlert(string msg) { uploadstatus += Environment.NewLine + $"[!Alert!]: " + msg; StateHasChanged(); } async ValueTask IAsyncDisposable.DisposeAsync() { if (dropInstance != null) { await dropInstance.InvokeVoidAsync("dispose"); await dropInstance.DisposeAsync(); } if (wrapper != null) { wrapper.Dispose(); } if (module != null) { await module.DisposeAsync(); } } }
3.就这么简单吗?我们还可以加上一些骚功能 ?? 粘贴文件上传
element.addEventListener('paste', function (e) { inputFile.files = e.clipboardData.files; const event = new Event('change', { bubbles: true }); inputFile.dispatchEvent(event); }, false);
4.限制传输格式
*时间有限,js部分同学们自己完成吧,这里是InputFile 上限制一下
<div style="padding-top:40px; padding: 20px; width: 200px; height: 200px; background-color: cornflowerblue; border: 2px dashed #0087F7; border-radius: 5px; "> 上传图片 <InputFile OnChange="OnChange" style="max-width: 400px" class="form-control" multiple accept='image/*' /> </div>
5.完整JS代码
export function init(wrapper, element, inputFile) { //阻止浏览器默认行为 document.addEventListener("dragleave", function (e) { e.preventDefault(); }, false); document.addEventListener("drop", function (e) { e.preventDefault(); }, false); document.addEventListener("dragenter", function (e) { e.preventDefault(); }, false); document.addEventListener("dragover", function (e) { e.preventDefault(); }, false); element.addEventListener("drop", function (e) { try { var 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) { wrapper.invokeMethodAsync('DropAlert', e); } }, false); element.addEventListener('paste', function (e) { inputFile.files = e.clipboardData.files; const event = new Event('change', { bubbles: true }); inputFile.dispatchEvent(event); }, false); return { dispose: () => { element.removeEventListener('dragleave', onDragLeave); element.removeEventListener("drop", onDrop); element.removeEventListener('dragenter', onDragHover); element.removeEventListener('dragover', onDragHover); element.removeEventListener('paste', handler); } } }
参考资料
用20行代码实现文件上传,浏览目录功能 (Blazor server) https://github.com/densen2014/Blazor100/wiki/9.-用20行代码实现文件上传,浏览目录功能-(Blazor-server)
HTML5拖放(drag and drop)与plupload的懒人上传 https://www.programminghunter.com/article/31061232701/
项目源码
知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系 。