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

在很多上传文件的应用实例中, 都可以看到[拖放文件到此上传]这种骚功能 ,今天我们就来试试Blazor能不能完成这个想法.

简述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.-%E7%94%A820%E8%A1%8C%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0,%E6%B5%8F%E8%A7%88%E7%9B%AE%E5%BD%95%E5%8A%9F%E8%83%BD-(Blazor-server)

HTML5拖放(drag and drop)与plupload的懒人上传 https://www.programminghunter.com/article/31061232701/


项目源码

Github | Gitee

关联项目

FreeSql QQ群:4336577(已满)、8578575(已满)、52508226(在线)

BA & Blazor QQ群:795206915、675147445

知识共享许可协议

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

AlexChow

今日头条 | 博客园 | 知乎 | Gitee | GitHub

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容