关于 element-ui 的 el-upload, 实际上 issue 中提到的次数也不少, 很多初试者可能 get 不到愉快使用的点, 提了 issue 之后又大多因为规范问题直接被机器人过滤或者关闭例如最近一次相关的 issue 是想寻求关于 http-request 的使用, 但也因为规范问题被直接关闭所以我们就稍微做一个比较接地气的业务类分享
0. 我们要什么?
这个问题就简单了: 首先, 我们需要一个好看的皮囊! 那 vue 基本没得选了, element-ui 的 el-upload 很符合口味其次, 我们需要一个有趣的灵魂, 我们是使用七牛的对象存储的, 但我们的想法是想使用 qiniu-js 这个官方的 SDK 因为 el-upload 开放了请求方法的自定义, 所以我们改造一下
1. 我们怎么做?
qiniu-js SDK
直接就看文档了
实际上为什么要直接用七牛的 SDK 而不是组件带的请求方法将就用一下就好呢? 这里我有两点可以解释: 稳定, 懒七牛放出来的东西肯定更适合他们自己的服务, 所以自己安排 action 啊或者 data 什么的可能会安排错, 那还不如直接按照他们给出的方式来做就行了比如分片, 如果只是从使用角度来看, 直接用 SDK 的话我就不用去关心到底要怎么分, 要怎么上传, 要怎么结合成一个文件我只需要让后端把上传策略都做好放出一个 token, 剩下的就什么都不用做了还有浏览器方面, 既然跟 Vue 一起使用了, 那么琐事 webpack 已经帮我们处理了, 我们根本不用关心
好了关于安装和引入就跳过了, 直接看方法如何调用简单看它的上传是以观察者形式, 通过 qiniu.upload 注册一个方法, 通过该方法进行订阅即上传操作, 取消订阅即取消上传操作而观察者又会拆分出三个方法: next, error, complete, 简单说就是管过程, 错误以及完成情况这部分可以直接依据文档写:
- const observable = qiniu.upload(file, key, token, putExtra, config)
- const subscription = observable.subscribe(next, error, complete) // 上传开始
- // subscription.unsubscribe() 这个方法可以取消操作
next 方法接收一个参数, 这个参数包含各种上传进度信息:
- const next = ({ total }) => {
- //
- const {
- loaded, // 已上传大小, 单位为字节
- total, // 本次上传的总量控制信息, 单位为字节
- percent // 当前上传进度, 范围: 0~100
- } = total
- };
所以如果你没有什么特殊需求的话, 只需要 percent 能捕获进度就行了
complete 接收一个参数, 当上传完整之后, 服务器按照配置给你返回的内容, 具体显示什么都看自己的后端如何配置
error 顾名思义就是当上传出现错误的时候做出处理, 对错误的处理也是因人而异, 直接看文档就行
至此先保留, 再看 el-upload
el-upload
我建议是去瞟一眼 el-upload 源码, 这样也方便理解, 当一个文件拖入或添加到组件的时候, 好看的皮囊和有趣的灵魂是如何协调工作的如果只是想理解上传的方式, 只看有出现 ajax 的两个文件就行: 一个是 ajax.js 还有一个是 upload.vue
如果你说: 我不想看源码! 然后又想能跟你写的请求方法结合, 可以! 有一个蠢方法: 先定义一个方法接收一个参数, 这个方法直接向 upload 的 http-request 进行绑定:
- {
- template: `<el-upload :http-request="request" />`
- methods: {
- request(obj) { console.log(obj) }
- }
- }
至此你就能看到 el-upload 打包的所有请求信息的了, 你就可以根据这个好看的皮囊设计灵魂了 (有一个 issue 提到关于 header 和 data 的问题, 实际上都会包含在这之中)
但我还是建议可以看一下源码, 因为你看了源码之后你就会发现一些细节等下可以用到, 比如 upload.vue 的 133~143 这几行代码:
- onProgress: e => {
- this.onProgress(e, rawFile);
- },
- onSuccess: res => {
- this.onSuccess(res, rawFile);
- delete this.reqs[uid];
- },
- onError: err => {
- this.onError(err, rawFile);
- delete this.reqs[uid];
- }
而这个时候你就能会知道: 噢! 我等下可以利用到这个皮囊的进度条显示, 成功以及失败的处理并不需要自己再去引入更多的组件或者更多的回调操作甚至如果以后不再用七牛作为请求方法, 组件也可复用不用修改所以 #8291 就有点可惜了, 如果他还没找到方法的话希望这篇文章可以帮到他
3. merge
弄清楚之后, 就是把他们揉起来对于 el-upload 能用的信息我们已经清楚, 剩下的关于业务上的操作就移步 element 的官方文档即可我们来制造灵魂, 在此之前注释一下: 我们团队是非常强调规范和拥抱
classes + TypeScript
这种方式的, 但写这篇文章的人是比较喜欢直接用 JavaScript, 而且应该更多人需要的是后者所以本次产出的渣代码用 JavaScript, 那么:
- // upload.js
- // token 找后端, obj 这里指代从 el-upload 接收到的 object
- export const upload = token => obj => {
- const { file } = obj
- // 关于 key 要怎么处理自行解决, 但如果为 undefined 或者 null 会使用上传后的 hash 作为 key.
- const key = ""
- // 因人而异, 自行解决
- const putExtra = {},
- config = {}
- const observable = qiniu.upload(file, key, token, putExtra, config)
- // 刚刚得到的信息可以使用了, 这样可以使用到 el-upload 的进度条
- const next = ({ total }) => obj.onProgress({ percent: total.percent })
- const error = err => obj.onError(err)
- const complete = res => obj.onSuccess(res)
- const subscription = observable.subscribe(next, error, complete)
- return subscription // 返回以方便取消上传操作
- }
- Vue.component('upload', {
- template: `<el-upload :http-request="request" />`
- methods: {
- request(obj) {
- // 你怎么搞到 token 我不管!
- const uploader = upload(token)
- const subscription = uploader(obj)
- }
- }
- })
这是一个抛砖引玉的操作, 大致上就只有这样了, 剩下全靠爱和定制就完事儿了!
来源: https://juejin.im/post/5ab5b069f265da239148102f