前端实现文件下载和拖拽上传 -new

参考:https://blog.csdn.net/ajujuju/article/details/112217431

<div contenteditable id="past-contener">
  This text can be edited by the user.
</div>
      const el = document.getElementById('past-contener');
      //此事件监听也可以添加在document上,该事件会有冒泡行为,则本页面上任何地方的粘贴操作都会触发
      el.addEventListener('paste', function(e){
        let file = null;
        const items = (e.clipboardData || window.clipboardData).items;
        if (items && items.length) {
          for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf('image') !== -1) {
              file = items[i].getAsFile();
              break;
            }
          }
        }
        if (file) {
          console.log(file);
          // 此时获取到file文件对象,即可处理上传相关处理
        }
       });


1文件拖拽:就是window是系统通过onchange事件监听 文件复制到input内容 如触发的事件
2.对应ui拖动事件就是 onDragOver onDrop onDragEnter 的拖动效果啊

    onDragOver(e) {
      console.log(e, "===DragOver");
    },
    onDragEnter(e) {
      console.log(e, "===DragOver");
    },
    onDrop(e) {
      console.log(e, "===DragOver");
    },

转载:https://blog.csdn.net/weixin_42817899/article/details/84330928?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163590192316780261999266%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163590192316780261999266&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-5-84330928.pc_v2_rank_blog_default&utm_term=%E5%89%8D%E7%AB%AF%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E4%B8%8B%E8%BD%BD%E8%BF%9B%E5%BA%A6&spm=1018.2226.3001.4450

需求
页面中增加下载示例按钮
实现一块区域能够拖拽上传word文件,限制文件大小2MB和文件类型,能显示进度条,同时支持取消上传。
文件下载
业务中要求的是示例放在静态文件夹中,并不需要请求后台。针对这种场景,笔者将介绍三种方法,分别是 window.open,form表单提交以及a标签 下载。笔者将通过下载img和word文档的例子,对这三种方法进行对比。

现构建dom结构如下:

<button onClick={this.windowOpen}>window.open</button>
<button onClick={this.formSubmit}>formSubmit</button>
<button onClick={this.aDownload}>aDownload</button>
方法一:使用 window.open :
import gakkiURL from './gakki.jpg';
import wordURL from './wordURL.doc';
windowOpen = () => {
    window.open(gakkiURL);
    //window.open(wordURL);
}

该方法在请求两种文件时,具体表现为:

img:新开网页,然后显示对应的img图片。

word:下载该文件。

方法2:使用form表单的submit:

formSubmit = () => {
    let form = document.createElement('form');
    form.method = 'get';
    form.action = gakkiURL;
    //form.action = wordURL;
    //form.target = '_blank';   // form新开页面
    document.body.appendChild(form); // form表单做出提交操作要先加入到dom树中
    form.submit();
    document.body.removeChild(form);
}

该方法在请求两种文件时,具体表现为:

img:form在不设置target时,会在当前页面打开url,显示图片。

word:下载该文件。

从上述两种方法可以看出,在请求对应的url时, 浏览器针对不同的MIME类型会选择不同的处理方式 。在请求img、txt等格式时,浏览器会打开对应的文件,而不是下载。如果想要img这些格式也下载呢?此时就需要方法三。

方法3:使用a标签:
// 使用a标签

aDownload = () => {
    const a = document.createElement('a');
    a.href = gakkiURL;
    //a.href = wordURL;
    //a.download = 'gakki.jpg';
    a.click();
}

a标签在不加download属性时表现同上两种方法,而在加了 download 属性后,可成功触发img等格式的下载。

download:
该属性可以设置一个值来规定下载文件的名称。所允许的值没有限制,浏览器将自动检测正确的文件扩展名并添加到文件 (.img, .pdf, .txt, .html, 等等)。

最终对比效果:

文件拖拽上传
文件上传
常用方法是使用 type=“file” 的input标签触发下载,然后使用formData传输数据,代码如下:

// 点击上传文档

handleClick = () => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document'; // word文件对应的MIME类型
    input.onchange = (e) => {
        const file = e.target.files.items(0);// files[0]也行
        console.table(file);
        // 检查文档格式
        if (!this.checkDocument()) {
            e.target.value = '';
            return;
        }
        // 上传文档
        this.uploadDocument(file);
    };
    input.click();
};
accept :表明input接受的文件的MIME类型。.doc和.docx相应的MIME类型在源码中已标明。

fileList对象可通过items或数组索引的形式获得对应的file对象。file对象常用的属性有:lastModified、type、name和size。可通过这些属性自定义检查文档格式。

检查文档的代码checkDocument如下:

// 文档检查

checkDocument = file => {
    const accept = ['.doc', '.docx'];
    const index = file.name.lastIndexOf('.');
    if (index < 0 || accept.indexOf(file.name.substr(index).toLowerCase()) < 0) { // 检查文件类型
        Message.error('暂不支持该文件格式');
        return false;
    }
    if (file.size > 2 * 1024 * 1024) { // 检查文件大小
        Message.error('文档大于2MB,上传失败');
        return false;
    }
    return true;
};

之后是上传文档uploadDocument:

// 上传文档

uploadDocument = file => {
    const index = file.name.lastIndexOf('.');
    const fileName = file.name.slice(0, index);
    const formData = new FormData();
    formData.append('file', file);
    // ajax、fetch或axios等方式上传
    ...
};

上传文档后需要去获取上传进度显示进度条,下面将对 ajax、fetch和axios对progress事件的支持情况 分别予以介绍。

Ajax
原生支持progress事件,可用于获取上传进度和下载进度,分别为 xhr.upload.onprogress 和 xhr.onprogress 事件。代码如下:

xhr.upload.onprogress = ev => console.log((ev.loaded / ev.total) * 100)

另外可以使用 xhr.abort() 取消文件上传。

Fetch
不支持progress事件,所以无法获取上传进度。但是笔者在查阅资料时发现由于res.body是可读字节流对象,所以可以使用res.body对象支持的 getReader() 属性获得 下载进度,具体文献请参考 jakearchibald.com/2016/stream… 。此处代码与上传的需求无关,仅作为fetch的相关拓展,可直接跳过这一段。

res.body.getReader() 方法用于读取响应的原始字节流,该字节流是可以循环读取的,直至body内容传输完成;

fetch(url, options).then(res => {
    let reader = res.body.getReader();
    let loaded = 0;
 
    // read()方法返回一个promise,接受值时resolve。
    reader.read().then(function processResult(result) {
        // result对象有两个属性:
        // done:完成时为true
        // value 数据
        if (result.done) { // 完成时退出循环
            console.log("Fetch complete");
            return;
        }
 
        loaded += result.value.length;// 长度,单位:字节
        console.log('Received', loaded, 'bytes of data so far');
 
        // 循环读取
        return reader.read().then(processResult);
    });
});

Axios
通过 onUploadProgress 和 onDownloadProgress 实现上传和下载。

onUploadProgress(ev) => {
    length = Math.round((ev.loaded / ev.total) * 100);
    console.log(length);
}
axios使用 cancel token 取消请求

var CancelToken = axios.CancelToken;
var source = CancelToken.source();
 
axios.get(url, {
  cancelToken: source.token
})
 

source.cancel();//取消请求
总结
ajax和axios对progress事件都进行了很好地支持,而fetch由于缺少对progress事件的支持在这里无法使用。

拖拽事件
实现了点击上传、获得上传进度以及取消上传等功能后,接下来要完成的是实现拖拽上传。实现前,我将对有关事件进行介绍。 首先是拖拽物体时发生的事件: onDragStart, onDrag 和 onDragEnd ,事件与被拖拽的物体有关。

onDragStart :拖拽开始

onDrag :拖拽中持续触发

onDragEnd :拖拽结束,无论是否可以放置均触发事件

然后是放置文件时要触发的事件: onDragEnter , onDragOver , onDragLeave 和 onDrop ,事件与要拖放进的区域有关。

onDragEnter :拖拽的物体进入时触发

onDragOver :拖拽的物体在区域中拖动时持续触发

onDragLeave :拖拽的物体离开区域时触发

onDrop :拖拽的物体放置在区域中时触发

项目中为了能够拖拽word文档,需要在容器上取消该容器默认的onDragEnter和onDragOver事件,这是因为:

事件的侦听器 dragenter 或 dragover 事件被用来表示有效的 drop 目标,也就是拖放项目可能被 dropped 的地方。web页面或应用程序的大多数区域都不是 drop 数据的有效位置。因此,这些事件的默认处理是不允许出现 drop。

如果您想要允许 drop,您必须通过取消事件来防止默认的处理。您可以通过从attribute-defined 事件监听器返回 false ,或者通过调用事件的 preventDefault 方法来实现这一点。后者在一个单独的脚本中定义的函数中可能更可行。

dom结构如下:

<div
    styleName="dropbox"
    onDragOver={this.preventDefault}
    onDragEnter={this.preventDefault}
    onDrop={this.handleDrop}
    >
    <div styleName="word-img" />
    {this.renderBtnByUpload(this.state.uploadStatus)} // 根据上传状态决定是"上传文件"还是"取消上传"
</div>
在将文件拖拽到内容区放置后,可以通过 dataTransfer 对象获得file信息。最终的handleDrop事件如下:

// 拖拽上传
handleDrop = (e) => {
    const file = e.dataTransfer.files[0];
    if (e.dataTransfer.files.length > 1) {
        Message.error('仅支持上传一个word文件');
        return;
    }
    if (!this.checkDocument(file)) {
        // 上传失败直接退出
        e.target.value = '';
        return;
    }
    this.uploadDocument(file); // 上传文件
}

总结
最终,实现的总体思路就是,首先构建放置文件的容器,然后给该容器取消默认的 onDragOver和 onDragEnter 事件,当拖拽文件到容器中时通过 dataTransfer.files 拿到文件并上传,使用ajax或axios等方式提供的progress事件拿到长度,将该长度传到progressBar组件中,最后展示出来。

本次给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
对web开发技术感兴趣的同学,欢迎加入Q群:943129070,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。

转载:https://blog.csdn.net/weixin_42817899/article/details/84330928

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值