业务背景
- 最近接了一个用
iview
为基础搭建的vue项目,在开需求研讨会议的时候,我个人提了一个柑橘很合理且很常规的建议,upload上传文件
支持同时上传多个
并且可限制数量
。当时想的是这不应该很正常吗,但是尴尬的是:只有multiple 开启选项,并无limit属性。
初始解决问题的思路
- 通过业务代码来控制
- 但是尴尬的是,搞了三个小时硬是没有成功解决这个问题
- 引入第三方插件
- 这个感觉是最简单的方案了,但是这好像
不是我的风格
,为了一个小功能点去引入一个插件。 - 直接放弃
- 这个感觉是最简单的方案了,但是这好像
- 修改源代码
- 这是当发现我通过业务代码无法解决问题后的常规想法
如何修改源代码呢
- 幸好,在不久的半年前我手撸过
element ui
的upload源代码
,二者结合一下吧,让iview适当抄袭下element ui
element ui 源代码里的 upload 组件限制上传数量代码如何实现的呢?
-
在props里定义了
limit
接收字段,
-
在input type="file"的
on-change
事件里调用的uploadFiles
方法中做好 数量限制的逻辑判断
uploadFiles 整体函数代码
js
uploadFiles(files) {
if (this.limit && this.fileList.length + files.length > this.limit) {
this.onExceed && this.onExceed(files, this.fileList);
return;
}
let postFiles = Array.prototype.slice.call(files);
if (!this.multiple) { postFiles = postFiles.slice(0, 1); }
if (postFiles.length === 0) { return; }
postFiles.forEach(rawFile => {
this.onStart(rawFile);
if (this.autoUpload) this.upload(rawFile);
});
},
核心代码
js
if (this.limit && this.fileList.length + files.length > this.limit) {
this.onExceed && this.onExceed(files, this.fileList);
return;
}
具体逻辑
当前文件列表的长度
+这次上传的文件长度
>总计限制的数量
- 即抛出异常,并拦截
iview 如何实现的呢?并且有什么问题呢
- 压根就没有传入limt限制最大上传数量字段
- 没有传入
数量超出
的异常回调函数
- uploadFiles 方法
并没有
进行当前文件列表的长度
+这次上传的文件长度
>总计限制的数量
,- 即抛出异常,并拦截 的逻辑处理
- 没有将次此上传的多个文件列表抛出到调用的业务组件,故无法通过业务层拦截
- 而是将文件列表循环一个个依次抛出
- 直接导致了iview 内部的 upload件底层没有做最大数量的拦截、同时也无法通过业务层代码进行拦截,
核心代码
js
handleChange (e) {
const files = e.target.files;
if (!files) {
return;
}
this.uploadFiles(files);
this.$refs.input.value = null;
},
uploadFiles (files) {
let postFiles = Array.prototype.slice.call(files);
if (!this.multiple) postFiles = postFiles.slice(0, 1);
if (postFiles.length === 0) return;
postFiles.forEach(file => {
this.upload(file);
});
},
核心问题代码
少了
js
if (this.limit && this.fileList.length + files.length > this.limit) {
// 异常逻辑处理 建议从调用的业务代码定义好异常逻辑传入并且调用
}
完整逻辑
js
uploadFiles (files) {
if (this.limit && this.fileList.length + files.length > this.limit) {
// 异常逻辑处理 建议从调用的业务代码定义好异常逻辑传入并且调用
}
let postFiles = Array.prototype.slice.call(files);
if (!this.multiple) postFiles = postFiles.slice(0, 1);
if (postFiles.length === 0) return;
postFiles.forEach(file => {
this.upload(file);
});
},
问题已经找到了,但是如何接入业务代码项目中呢
考虑方案
- 直接改node_modules中源代码
不建议
,直接否定 ,理由如下- 在node_modules中源代码后需要,其他成员更新node_modules中源代码
- 无法提交到git中,因为不可能将node_modules放到git上
- 后期更新插件版本就会替换整个文件夹
- 故
直接否定
- 修改插件代码后放到
私有服务器
上不建议
,直接否定,理由如下- 后期插件版本升级了,如果想使用高版本的iview组件库,只能直接覆盖代码
- 接入私服后,
安装依赖只能在内网
,极其不方便
- 直接从iview组件库的upload组件中捞一份 upload的源代码,然后再新的文件中修改
最优解
- 以上问题都不会有
- 可扩展性强,且不会影响其他逻辑
如何调用组件
- 封装好组件后,直接调用
- 同时传递,limit(限制数量),以及数量超出的执行异常回调函数即可
致谢
- 感谢项目组给予我挑战自己的机会
- 感谢iview写出了让我感到诧异的bug
传递,limit(限制数量),以及数量超出的执行异常回调函数即可
致谢
- 感谢项目组给予我挑战自己的机会
- 感谢iview写出了让我感到诧异的bug
- 感谢element ui 的完美源代码给予了我学习和参考并实践的机会