『设计』ES6原生实战Uploader工具类(从设计到实现)( 二 )
初始化 - _init 这里初始化做了几件事:维护一个内部文件数组uploadFiles , 构建input标签 , 绑定input标签的事件 , 挂载dom 。
为什么需要用一个数组去维护文件 , 因为从需求上看 , 我们的每个文件需要一个状态去追踪 , 所以我们选择内部维护一个数组 , 而不是直接将文件对象交给上层逻辑 。
由于逻辑比较混杂 , 分多了一个函数_initInputElement进行初始化input的属性 。
class Uploader {// ..._init () {this.uploadFiles = [];this.input = this._initInputElement(this.setting);// input的onchange事件处理函数this.changeHandler = e => {// ...};this.input.addEventListener('change', this.changeHandler);this.setting.wrapper.appendChild(this.input);}_initInputElement (setting) {const el = document.createElement('input');Object.entries({type: 'file',accept: setting.accept,multiple: setting.multiple,hidden: true}).forEach(([key, value]) => {el[key] = value;})''return el;}}
看完上面的实现 , 有两点需要说明一下:
- 为了考虑到destroy()的实现 , 我们需要在this属性上暂存input标签与绑定的事件 。 后续方便直接取来 , 解绑事件与去除dom 。
- 其实把input事件函数changeHandler单独抽离出去也可以 , 更方便维护 。 但是会有this指向问题 , 因为handler里我们希望将this指向本身实例 , 若抽离出去就需要使用bind绑定一下当前上下文 。
为了更加贴合业务需求 , 可以通过事件返回结果来判断是中断 , 还是进入下一流程 。
this.changeHandler = e => {const files = e.target.files;const ret = this._callHook('choose', files);if (ret !== false) {this.loadFiles(ret || e.target.files);}};
通过这样的实现 , 如果显式返回false , 我们则不响应下一流程 , 否则拿返回结果||文件列表 。 这样我们就将判断格式不符 , 超出大小限制等等这样的逻辑交给上层实现 , 响应样式控制 。 如以下例子: uploader.on('choose', files => {const overSize = [].some.call(files, item => item.size > 1024 * 1024 * 10)if (overSize) {setTips('有文件超出大小限制')return false;}return files;});
状态事件绑定与响应 简单实现上文提到的_callHook , 将事件挂载在实例属性上 。 因为要涉及到单个choose事件结果控制 。 没有按照标准的发布/订阅模式的事件中心来做 , 有兴趣的同学可以看看tiny-emitter的实现 。class Uploader {// ...on (evt, cb) {if (evt && typeof cb === 'function') {this['on' + evt] = cb;}return this;}_callHook (evt, ...args) {if (evt && this['on' + evt]) {return this['on' + evt].apply(this, args);}return;}}
装载文件列表 - loadFiles 传进来文件列表参数 , 判断个数响应事件 , 其次就是要封装出内部列表的数据格式 , 方便追踪状态和对应对象 , 这里我们要用一个外部变量生成id , 再根据autoUpload参数选择是否自动上传 。let uid = 1class Uploader {// ...loadFiles (files) {if (!files) return false;if (this.limit !== -1 &&files.length &&files.length + this.uploadFiles.length > this.limit) {this._callHook('exceed', files);return false;}// 构建约定的数据格式this.uploadFiles = this.uploadFiles.concat([].map.call(files, file => {return {uid: uid++,rawFile: file,fileName: file.name,size: file.size,status: 'ready'}}))this._callHook('change', this.uploadFiles);this.setting.autoUpload && this.upload()return true}}
- 【济南】公开征求意见 | 济南遥墙国际机场二期改扩建工程航站区规划设计方案
- IT极客世界“拒绝”平庸设计,小米MIX4渲染图曝光,堪称“颜值”奇迹
- IT极客世界小米MIX4渲染图曝光,堪称“颜值”奇迹,“拒绝”平庸设计
- 数码科技大爆炸前魅族高管李楠再放狠话!华为旗舰机瀑布屏设计没用:只是炒作概念
- 我家的猫叫皮蛋台积电急了,纯国产芯片来了,华为设计,中芯生产你如何评价?,ASML断供失效
- 热门数码后置4摄颠覆性设计,华为P50Pro概念图:机身四曲面双长焦镜头
- 热门数码华为P50Pro概念图:机身四曲面双长焦镜头,后置4摄颠覆性设计
- 梦回旧景好梦一场世界各国都重新设计生活设施,开启“一米帽”式新生活,疫情之下
- 大数据邦新基建之大数据中心规划设计原则和内容,选址很关键
- 七九数码资讯手机外观设计越来越重要,良好的辨识度可以让一部手机脱颖而出