• Blazor 使用拖放(drag and drop)上传文件 , 粘贴文件上传


    在很多上传文件的应用实例中, 都可以看到[拖放文件到此上传]这种骚功能 ,今天我们就来试试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>
    

    代码

    1. InputFile 开启 multiple ,接受多文件上传
    2. 使用JS隔离技术
    3. 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/

    项目源码

    Github | Gitee

    知识共享许可协议

    本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

  • 相关阅读:
    wondows10用Electron打包threejs的项目记录
    【变分法】【书籍阅读笔记】Calculus of Variation by gelfand 第一章 总结与习题题解 【更新中】
    公司刚来了个腾讯拿 35K 出来的,真是砂纸擦屁股,给我露了一手啊
    Spring Security实现统一登录与权限控制
    Linux内存管理(三十二):直接内存规整详解
    vue大型电商项目尚品汇(后台篇)day02
    数字方法_toLocaleString方法
    解决npm报错Error: error:0308010C:digital envelope routines::unsupported
    Arthas 启动时无法获取java进程
    react 使用useRoutes遇到的问题
  • 原文地址:https://www.cnblogs.com/densen2014/p/16128246.html