来源 | OSCHINA 社区
作者 | 京东云开发者-京东物流 刘海鼎
背景
前端文件上传本来是一个常规交互操作,没什么特殊性可言,但是最近在做文件上传,需要实现截图粘贴上传,去找了下有没有什么好用的组件,网上提供的方法有,但是没找完整的组件来支持 cv 上传,经过了解发现可以用剪贴板功能让自己的 cv 实现文件上传,于是自己就整合了目前几种文件上传的交互方式,码了一个支持 cv 的 vue3 文件上传组件(造个轮子)。
介绍
作为一个完整的组件内容还是挺多的,这里主要介绍下上传交互中一些主要功能,包括上传的几种交互方式, 上传进度的获取,上传类型的限制,默认上传请求和自定义上传请求。 以下代码都是非完整代码,大家用于参考实现过程,可以通过以下代码修改来完成自己想要的交互功能。
几种交互
1,点击选择上传
点击选择是最常见的上传交互,之前原生上传控件,样式修改比较麻烦,为了修改上传样式,我们可以把该控件设置隐藏,用其他元素通过从 click 交互,来触发该文件选择控件。在选择文件控件上绑定 onchange 事件,该控件在 change 后获取到文件,然后调用上传方法,实现如下:
2,拖动上传
3,复制上传(复制检测区域设置)+
+
上传模式
根据以上三种交互,大家可自由组合上传形式,比如点击和拖拽,拖拽和粘贴组合等等,我这边目前按点击,拖拽,粘贴叠加组合,设置为:
・点击上传,click
・拖拽上传 drag(包括点击上传和拖拽上传)
・粘贴上传 paste (包括点击,拖拽和复制上传)
通过传参 uploadeMode 设置 (click, drag, paste)
组件设置:
+ +
组件应用
点击上传
文件限制
文件限制包括是否多文件上传限制 multiple, 上传数量 limit 限制,上传类型 accept 限制,这些设置参考了 element-plus 上传组件,在其基础上做了简化。实现如下 multiple 和 accept 首先需要在点击控件上绑定,以便于在点击选择上传时就能够过滤对应文件,拖拽上传和粘贴上传,无法通过 input [type=file] 组件控制需要在上传方法中判断过滤,(以粘贴上传为例) 组件实现
+
上传进度设置
获取文件上传进度,使用 ajax 中的 progress 事件监听机制,回传数据 loaded 进度,和 ttotal 进行计算,获取到计算的百分比通过 process 插槽线上在界面上。 具体实现如下: 组件实现 文件限制后执行组件上传,默认情况下走内置的上传方法,如果做了自定义,上传进度也需要自己实现(自己实现过程可以参考内置方法中的实现)
// 上传方法调用
ajaxUpload({...props, file})
// 上传方法实现
ajaxUpload = (options) => {
const xhr = new XMLHttpRequest()
const action = option.action
console.log(xhr, xhr.upload)
if (xhr.upload) {
// 建立progress监听
xhr.upload.addEventListener('progress', (evt:any) => {
const progressEvt = evt
progressEvt.percent = evt.total > 0 ? (evt.loaded / evt.total) * 100 : 0
// 回传进度数据
option.onProgress(progressEvt)
})
}
}
同样文件上传成功,异常等方法也可以通过监听 load 并且判断 xhr.status 来实现,
xhr.addEventListener('load', () => {
if (xhr.status < 200 || xhr.status >= 300) {
return option.onError(getError(action, option, xhr))
}
option.onSuccess(getBody(xhr))
})
组件使用 ・配置获取进度数据回调函数 onProgress ・配置接收回传的进度数据进行赋值 ・配置进度条插槽显示进度数据
自定义上传请求 {{progressval}} %
// 上传文件
const uploadFiles = (files) => {
if (files.length === 0) return
const { limit, multiple, accept, httpRequest } = props
// 是否多文件限制,主要用于拖拽和粘贴上传中
if (!multiple) {
files = Array.from(files).slice(0, 1)
}
// 文件数量
if (limit && files.length > limit) {
/*具体大家需要的逻辑可自行定义*/
return
}
// 文件类型限制
if (accept) {
files = filesFiltered(Array.from(files), accept)
}
//在文件符合条件后执行上传方法
// 自定义上传方法调用
if(httpRequest) {
return httpRequest(files)
}
}
组件应用: 注意点: 通过自定义上传方法实现时,在原来组件上的属性 action 无效
{{progressval}} %
总结
通过以上可以实现一个支持多种交互方式的文件上传组件,同时也将 element-plus 中文件上传的流程做了一个学习,因为该组件的实现过程就是参考了 element-plus 的实现,在 element-plus 上传的基础上添加了粘贴上传交互,该组件的实现重在交互方式,各个样式风格通过插槽自定义。
全部0条评论
快来发表一下你的评论吧 !