使用原生 JS 的前端 + koa2搭建一个拖拽文件上传的服务接口,用作学习练手以及自己使用的图床
- 初始时简单完成:
- 文件上传接口
v0.1.0
- 拖拽相关操作
v0.2.0
- 图床上的图片链接
v1.0.0
- laobubu提出的根据一个 url 拿到需打印文档的服务,现在可以在打印店里访问
https://i.setsuna.wang
来打印
- 文件上传接口
- 额外的需求:
- 图片以外的缩略图处理,例如
.md .css .doc .ppt .pdf
v1.1.0
- clipboard 支持
- 图片切割
image?width=200&height=200/webp
- 后期前端页面切换为
vuetify
+nuxt
- 增加第三方的图床 API
- sm.ms
- 七牛云
- 针对三家图床API(包括自己)使用图标颜色来标注
宕机
or正常服务中
- 对访客进行统计
直接赋值后运行会报错, 报错的原因是 querySelectorAll
所需的执行上下文必需是 document
,而我们赋值到 $
调用后上下文变成了全局 window
,正确的应该是
var $ = document.querySelector.bind(document);
var $$ = document.querySelectorAll.bind(document);
需要注意的地方是,这些方法返回的要么是单个 Node 节点,要么是 NodeList 而 NodeLis 是类数组的对象,但并不是真正的数组,所以拿到之后不能直接使用 map,forEach 等方法。正确方法:
Array.prototype.map.call(document.querySelectorAll('button'),function(element,index){
element.onclick = function(){
}
})
目前只能通过表单选择文件
或者拖拽文件
或者剪切板事件
document.querySelector('input').onchange = function() {
console.log(this.files);
};
//或者拖拽事件
var ipt = document.querySelector('textarea');
ipt.ondragover = function () { return false; };
ipt.ondrop = function(e) {
e.stopPropagation();
e.preventDefault();
e = e || window.event;
var files = e.dataTransfer.files;
console.log(files);
};
name
:文件名,该属性只读。size
:文件大小,单位为字节,该属性只读。type
:文件的 MIME 类型,如果分辨不出类型,则为空字符串,该属性只读。lastModified
:文件的上次修改时间,格式为时间戳。lastModifiedDate
:文件的上次修改时间,格式为 Date 对象实例。
readAsText(Blob|File, opt_encoding)
:返回文本字符串。默认情况下,文本编码格式是’UTF-8’,可以通过可选的格式参数,指定其他编码格式的文本。readAsDataURL
注意:
FileList
这个对象不是很严谨,它的 length 和 item 等等都能被map
或for..in
访问到,因此只能使用for(var i = 0;i<FileList.�length;i++)
来遍历
- 事件
onabort
事件:读取中断或调用reader.abort()方法时触发。onerror
事件:读取出错时触发。onload
事件:读取成功后触发。onloadend
事件:读取完成后触发,不管是否成功。触发顺序排在 onload 或 onerror 后面。onloadstart
事件:读取将要开始时触发。onprogress
事件:读取过程中周期性触发
- 点击文件选择并通过选择文件使得
#fileInput
元素触发change
事件 => 执行funGetFiles
函数funGetFile
函数中依次执行funDragHover
- 如果此时
e.type
是dragover
就执行onDragOver
函数 - 否则执行
onDragLeave
函数
- 如果此时
- 从
fileFilter
中读取file
并使用new FileReader()
对应的readAsDataURL(file)
来把 base64编码的图像放入 DOM 中 ,其中把 onload 事件回调封装为了 Promise调用的时候使用readFile: function (file) { return new Promise((resolve, reject) => { var reader = new FileReader() reader.onload = e => { resolve(e.target.result) } reader.onerror = e => { reject('readFile error!') } reader.readAsDataURL(file) }) },
await this.readFile(files[i])
即可
- 点击确认上传 => 执行
funUploadFile
函数- 从
fileFilter
中取出文件并创建XMLHttpRequest()
来以 POST 形式发送new FormData()
- 若
xhr.readyState == 4 && xhr.status ==200
执行onSuccess(file,xhr.responseText)
回调 - 若
xhr.status != 200
执行onFailure(file,xhr.responseText)
回调 - 当
fileFilter.length为0
时执行onComplete
回调, 通常什么也不做
- 从
DataTransfer对象
可通过e.Datransfer
访问- 相关事件有
dragstart | dragenter | dragleave | dragover | drop | dragend
- 标准属性有
- 常用:
dropEffect
常用来设置鼠标的脚标样式 有none|copy|link|move
四个可选值
注:有人说该属性仅在
dragover
事件中设置才有效.经测试在dragleave
事件中设置该属性时,Firefox 62.0.3
支持/Chrome 69.0
不支持. 另外,建议使用dragover
事件而非dragenter
事件,因为dragenter
内设置的dropEffect
无法在后续的拖动过程中显示.且enter+drop
的组合会遇到drop
不生效的问题,hover+drop
则正常- 常用:
files
用来获取被拖拽的文件 - 不常用:
effectAlowed | items(只读) | types(只读)
- 常用:
- 标准方法:详细见鑫空间
- 在 div 上绑定
ondrop
事件等等可能会被子元素(如图片)等触发, 解决方法是在有drag 操作时添加一个 drag 的 className,然后添加 css . 这样可以不影响 hover 伪元素.drag *{ pointer-events: none; }