首先介绍几个要用到的知识点,源码地址在最底部,不想看文字的同学可以直接拉到最底部下载。
一、知识点
实现拖拽上传需要用到的知识点如下:
前端
拖拽事件
dataTransfer
FileReader
FormData
progress
后端
multer
fs.renameSync
1.H5拖拽事件
我们拖动图片放到一个div上时,下列事件会依次发生:
- dragenter
- dragover
- dragleave或drop
只要图片被拖动到div上,就会触发dragenter事件,类似于mouseover事件。
紧接着是dragover事件,而且只要图片在div内移动,就会不停的触发。
如果拖出了div的范围,dragover事件不再发生,但会触发dragleave事件。
如果你拖着图片在div上松手了,就会触发drop事件。
2.dataTransfer对象
只有简单的拖放而没有数据变化是莫得用的。我们拖个图片进来的目的是啥?当然是为了获得图片数据,这样才能然后传到服务器上去。于是有了dataTransfer对象,它是事件对象的一个属性,用于从被拖动元素向放置目标传递字符串格式的数据。我们要完成拖拽上传图片就得靠这个对象,因为它是事件对象的属性,所以我们只能在事件处理程序中使用,参考以下代码:
//在drop事件中使用dataTransfer对象
onDrop: function(e) {
console.log("松手");
var dt = e.dataTransfer;
}
3.FormData
MND文档
具体的用法还是得阅读MDN文档好,以下是本菜鸡读了文档后对FormData的理解:
首先明确FomeData是一个对象,由键值对组成,有个append()方法增加键值,我们可以append字符、数值或是文件
var formData = new FormData();
formData.append("name", "Ciger");
formData.append("phone", 123456); //数字123456会被立即转换成字符串 "123456"
// HTML 文件类型input,由用户选择
formData.append("userfile", fileInputElement.files[0]);
append后,我们可通过get()和set()操作对象的值
formData.get('name') // 获取值-> Ciger
formData.set('name','Ciger2') //重置值-> Ciger2
知道如何使用这个对象了,最关键的就是它有什么用?
formData的作用有两个:
- 用于发送表单数据,也可独立于表单使用
- 上传文件
独立于表单使用有点抽象,我们来看代码。
代码里是一个form表单,有两个input输入框加一个提交按钮。通常来说,我们提交数据时要先获取到两个input框的数据,拼接在一起,然后通过ajax发送。
有了FormData对象,两行代码就可以实现form对象数据的拼接
var form = var form=document.querySelector("#myForm");;
var data = new FormData(form);
上述代码的data都是form表单里的填的,独立于表单使用即代表我们可以不需要html元素,直接生成数据,然后发送给后端。
来看下面的上传文件代码
var file = e.dataTransfer.files[0] //通过dataTransfer获取拖拽过来的文件
var formData = new FormData()
formData.append('file',file)
//ajax发送formData
...
xhr.send(formData)
4.FileReader
MDN文档
FileReader对象是用来读取文件的,我们可以通过new FileReader(file)
创建一个FileReader对象,file参数代表要读取的文件,可以来自用户在一个
元素上选择文件后返回的FileList对象,也可以是拖放操作生成的DataTransfer对象
FileReader有如下事件:
- onabort
- onerror
- onload
- onloadstart
- onloadend
- onprogress
我们可以通过这些事件实现图片的预览,代码如下:
var fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = function() {
console.log(this.result)
//这里的this指向是FileReader对象!!!
//这里的this指向是FileReader对象!!!
//这里的this指向是FileReader对象!!!
//将图片的地址src设置为this.result即可
}
注意!!读取后的结果会存在onload事件中的this.result中!
5.进度事件(Progress)
progress事件是针对XHR操作的,会在浏览器接受新数据期间周期性的触发,而onprogress事件处理程序会接收到一个events对象,其target属性是XHR对象,但包含了三个额外的属性
- lengthComputable 进度信息是否可用
- position 已接收到的字节数
- totalSize 根据Content-Length响应头部确定的预期字节数
有了这些信息,我们就可以为用户创建一个上传进度条
var xhr = createXHR();
xhr.onload = function () {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
};
//post一般用来获取上传进度
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
console.log(e.loaded / e.total * 100)
}
}
二、前端代码
Document
将文件拖到这里
{{ file.name }}
代码解析
- HTML部分有个ref="dropbox"的div,这个就是我们的拖拽区域
...
...
- JS部分,mounted的时候,对dropbox添加拖拽事件的监听
mounted: function() {
var dropbox = document.querySelector(".dropbox");
dropbox.addEventListener("dragenter", this.onDrag, false);
dropbox.addEventListener("dragover", this.onDrag, false);
dropbox.addEventListener("dragleave", this.onDragLeave, false);
dropbox.addEventListener("drop", this.onDrop, false);
}
3.methods中实现这几个事件函数
upload(){} //上传文件方法
onDrag(){}
onDragLeave(){}
onDrop(){}
//具体实现看上述代码
三、后端代码
var fs = require("fs");
var express = require("express");
var multer = require("multer");
var app = express();
var upload = multer({ dest: "upload/" });
//设置跨域访问
app.all("*", function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", " 3.2.1");
// res.header("Content-Type", "application/json;charset=utf-8");
next();
});
// 多图上传
app.post("/upload-multiply", upload.array("file", 2), function(req, res, next) {
var files = req.files;
var fileName = "";
if (files.length > 0) {
files.forEach(item => {
fileName = new Date().getTime() + "-" + item.originalname;
fs.renameSync(item.path, __dirname + "\\upload" + "\\" + fileName);
});
res.send({ code: 1, url: "127.0.0.1:3000/upload/" + fileName });
} else {
res.send({ code: 0 });
}
});
app.listen(3000);
后端需要npm install express multer
运行前要先创建upload文件夹用于存放文件
四、源码与总结
源码地址:https://github.com/C-Utopia/pratice-project.git
之前一直对H5的拖拽事件和文件上传迷迷糊糊,所以做了这个小练习。
遇到没做过的东西,首先上网搜索,例如我想实现拖拽上传,那就在百度搜索vue拖拽上传文件之类的关键词,先看看别人如何实现的,复制别人的代码下来看能不能运行,要是能成功运行则仔细阅读源码,源码有没见过的单词,如FormData、FileReader,直接上MDN看文档,了解清楚这个知识点之后再继续阅读源码。
了解清楚拖拽上传的相关知识点以及实现思路,我们再动手写代码就是水到渠成的事了。