ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

cube-ui Upload 组件完全指南:文件对象模型、上传配置与源码级解析

cube-ui Upload 组件完全指南:文件对象模型、上传配置与源码级解析 前端UI组件移动开发【免费下载链接】cube-ui:large_orange_diamond: A fantastic mobile ui lib implement by Vue项目地址https://gitcode.com/gh_mirrors/cu/cube-ui点击查看免费下载本指南以 cube-ui 官方文档 document/components/docs/en-US/upload.md 为骨架系统讲解cube-upload上传组件的文件对象模型、Props 配置、事件与实例方法并逐一结合 src/components/upload/upload.vue、src/components/upload/ajax.js 与 src/components/upload/util.js 等源码说明底层实现。读完本文你将掌握从基础上传、文件校验、图片压缩 Base64 上传到完全自定义 UI 的完整实战方案。本文内容对应组件版本要求Upload组件自1.3.0起提供文中标注sup1.11.0/sup的配置项如action.target支持函数、checkSuccess的可选回调参数自1.11.0起生效file-click事件的index参数自1.12.39起提供。使用时请以实际安装版本为准。1. 文件对象file object模型文档中约定用户选中的原始文件称为original file经组件包装后的对象称为file object。所有事件回传、v-model双向绑定以及上传请求体中的数据都以 file object 为载体。其完整结构如下| Attribute | Description | Type | | - | - | - | | v-model | 文件列表 | Array默认[]如[{ name, size, url, status: success, progress: 1 }]| | name | 文件名 | String | | size | 文件大小 | Number | | url | 文件 URL由URL.createObjectURL生成用于预览 | String | | base64 | 文件的 base64 值与原文件 base64 相等默认可通过插件如压缩插件写入 | String | | status | 文件状态ready、uploading、success、error| String | | progress | 上传进度数值 0~1 | Number | | file | 原始文件 | File | | response | 响应数据尝试解析为 JSON | Object/Array/String | | responseHeaders | 全部响应头 | String |1.1 源码中的对象构造从源码看file object 由 src/components/upload/util.js 的newFile函数构造export function newFile(name , size 0, status , progress 0, file null) { const base64 (file file.base64) || const url base64 ? : createURL(file) return { name, size, url, base64, status, progress, file } }createURL在浏览器环境下调用window.URL.createObjectURL(file)生成预览 URL见 src/components/upload/util.js 对URL的兼容性处理依次取window.URL || window.webkitURL || window.mozURL。值得注意的细节是当 file object 已带有base64时url字段为空——预览将直接使用 base64 而非 ObjectURL这正是压缩插件写入 base64 后能直接预览的原因。状态常量同样定义在 src/components/upload/util.jsexport const STATUS_READY ready export const STATUS_UPLOADING uploading export const STATUS_ERROR error export const STATUS_SUCCESS success1.2 response 与 responseHeaders 的写入时机response与responseHeaders并非构造时存在而是在请求结束onload/onerror/ontimeout时由 src/components/upload/ajax.js 的setResponse写入function setResponse() { let response xhr.responseText || xhr.response try { response JSON.parse(response) } catch (e) {} file.response response file.responseHeaders xhr.getAllResponseHeaders() }可见组件会对响应文本尝试JSON.parse解析失败则保留原始字符串因此response的类型是 Object/Array/String 三选一与文档描述一致。2. 快速上手基础用法文档给出的最小可用示例cube-upload action//jsonplaceholder.typicode.com/photos/ :simultaneous-uploads1 files-addedfilesAdded /export default { methods: { filesAdded(files) { const maxSize 1 * 1024 * 1024 // 1M for (let k in files) { const file files[k] if (file.size maxSize) { file.ignore true } } } } }使用要点action配置 multipart POST 请求的上传目标 URLsimultaneous-uploads配置同时上传的最大文件数files-added事件用于文件校验通过设置file.ignore true过滤文件。在官方示例 example/pages/upload/default.vue 中同样的校验逻辑还会配合$createToast弹出「You selected 1M files」的警告提示并额外展示了实例方法start()/pause()/retry()与按钮联动upload() { this.isUploading true this.$refs.upload.start() }, pause() { this.isUploading false this.$refs.upload.pause() }, retry() { this.$refs.upload.retry() }2.1 ignore 标记如何生效addFiles 源码解析file.ignore是在 src/components/upload/upload.vue 的addFiles方法中被消费的addFiles(files) { this.$emit(EVENT_ADDED, files) const filesLen this.files.length const newFiles [] const maxLen this.max - filesLen let i 0 let file files[i] while (newFiles.length maxLen file) { if (!file.ignore) { newFiles.push(file) this.files.push(newFile()) } file files[i] } ... }从源码可以明确三个行为files-added事件在任何过滤之前最先触发因此校验逻辑必须在这个事件回调里同步修改file.ignore过滤受max限制只有newFiles.length max的文件会被接纳超出部分直接丢弃组件会先向files数组 push 一个newFile()占位待processFile异步处理完成后再通过$set用真实 file object 替换占位见 src/components/upload/upload.vue$set保证了数组更新的响应性。3. 图片压缩并通过 Base64 上传对于移动端常见的「拍照上传」场景直接上传原图既费流量又慢cube-ui 文档给出的方案是先压缩原图再以 Base64 字段提交。3.1 示例代码cube-upload refupload :actionaction :simultaneous-uploads1 :process-fileprocessFile file-submittedfileSubmitted/cube-uploadimport compress from ../../modules/image export default { data() { return { action2: { target: //jsonplaceholder.typicode.com/photos/, prop: base64Value } } }, methods: { processFile(file, next) { compress(file, { compress: { width: 1600, height: 1600, quality: 0.5 } }, next) }, fileSubmitted(file) { file.base64Value file.file.base64 } } }注文档示例中data里变量名为action2实际模板绑定的是action请以自己代码中的命名保持一致。关键点action为对象时包含target与propprop用于指定 file object 上的哪个属性作为上传字段process-file是一个处理原始文件的函数处理完成后必须调用next并传入处理后的文件file-submitted事件在文件处理完成、被加入upload.files后触发回调参数为 file object。3.2 processFile 与 file-submitted 的调用链在 src/components/upload/util.js 中processFiles/processFile实现了多文件的串行处理与回调汇总每个原始文件经processFile(file, next)处理后用返回值构造 file objectnewFile(file.name, file.size, STATUS_READY, 0, file)再通过eachCb回传——回到 src/components/upload/upload.vue 即执行this.$set(this.files, filesLen index, file) this.$emit(EVENT_SUBMITTED, file)所以file-submitted回调里拿到的file已经是一个包含url或base64、status: ready、progress: 0的完整 file object其file属性指向原始文件。示例中file.base64Value file.file.base64正是把压缩后写入原始文件对象上的base64字段搬运到 file object 上供prop: base64Value作为上传字段使用。3.3 压缩实现example/modules/image.js 源码解读仓库示例中的压缩插件位于 example/modules/image.js改编自腾讯 WeUI.js 的 uploader/image其核心compress(file, options, callback)流程如下FileReader.readAsDataURL读取文件为 base64若options.compress false不做压缩直接把 base64 写入file.base64并回调适用于「不压缩、直接 base64 上传」启用压缩时创建Image加载 base64通过detectVerticalSquash检测 iOS 拍照图片被压扁的 bug 并计算补偿比率通过getOrientation读取 JPEG EXIF 方向信息再用orientationHelper对 canvas 做旋转/翻转修正按compress.width/compress.height等比缩放宽高比不变只缩放到不超过上限canvas.toDataURL(image/jpeg, quality)输出压缩后的 base64上传方式分流options.type file时把 dataURL 转成 Blob 后回调否则把 base64 写入file.base64回调。若压缩失败;base64,null文件方式回退到原文件base64 方式直接调用options.onError报错。可见该插件为移动端「拍完即传」场景补全了三项能力方向修正、等比压缩、质量压缩。4. 使用插槽自定义 UIcube-upload 的默认渲染是「缩略图网格 加号按钮」分别由cube-upload-file与cube-upload-btn提供。文档演示了如何用插槽完全接管界面实现「点击上传身份证」这类单文件业务cube-upload refupload v-modelfiles :actionaction files-addedaddedHandler file-errorerrHandler div classclear-fix cube-upload-file v-for(file, i) in files :filefile :keyi/cube-upload-file cube-upload-btn :multiplefalse div i/i pPlease click to upload ID card/p /div /cube-upload-btn /div /cube-uploadexport default { data() { return { action: //jsonplaceholder.typicode.com/photos/, files: [] } }, methods: { addedHandler() { const file this.files[0] file this.$refs.upload.removeFile(file) }, errHandler(file) { // const msg file.response.message this.$createToast({ type: warn, txt: Upload fail, time: 1000 }).show() } } }配套的自定义样式stylus.cube-upload .cube-upload-file, .cube-upload-btn margin: 0 height: 200px .cube-upload-file margin: 0 .cube-upload-btn margin-top: -200px opacity: 0 .cube-upload-file-def width: 100% height: 100% .cubeic-wrong display: none .cube-upload-btn display: flex align-items: center justify-content: center div text-align: center i display: inline-flex align-items: center justify-content: center width: 50px height: 50px margin-bottom: 20px font-size: 32px line-height: 1 font-style: normal color: #fff background-color: #333 border-radius: 50%完整示例见 example/pages/upload/custom.vue。4.1 插槽机制与子组件说明从 src/components/upload/upload.vue 可以看到cube-upload根模板是一个带默认插槽的容器默认内容为「upload-file列表 upload-btn」一旦传入插槽内容默认 UI 整体被替换。插槽中可用的两个子组件均由cube-upload内部注册见 src/modules/upload/index.jscube-upload-file接收fileprop 渲染单个文件。其实现 src/components/upload/file.vue 提供两个具名插槽参数img-style背景图样式优先取file.url其次取file.base64与progress百分比文本如42%success/error状态直接显示100%。文件右上角的删除角标内部触发removeFile经$parent.removeFile调用组件方法。点击文件会冒泡click事件由cube-upload统一转发为file-clickcube-upload-btn内部包含一个透明的input typefile见 src/components/upload/btn.vue其change事件把fileEle.files传给this.$parent.addFiles(files)并立即将 input 的value置空——这样重复选择同一文件也能触发change。multiple与accept属性由公共 mixin src/components/upload/btn-mixin.js 提供multiple默认trueaccept默认image/*。4.2 单向删除技巧addedHandler中this.files[0]与this.$refs.upload.removeFile(file)的组合实现「只允许上传一张、新选择即替换旧文件」。removeFile内部见 src/components/upload/upload.vue会依次发出file-removed事件 → 若存在file._xhr则abort()中断请求 →URL.revokeObjectURL(file.url)释放预览 URL防止内存泄漏→ 从files中splice删除 → 重新调用upload()推进后续任务。5. Props 配置全表与源码印证| Attribute | Description | Type | Accepted Values | Demo | | - | - | - | - | - | | v-model | 文件列表 | Array |[]|[{ name, size, url, status: success, progress: 1 }]| | action | 上传配置 | String/Object ||{ target: /upload }| | max | 最大上传文件数 | Number |10| - | | auto | 是否自动开始上传 | Boolean |true| - | | simultaneousUploads | 同时上传数量 | Number |1| - | | multiple | 是否多选 | Boolean |true| - | | accept | input 的 accept | String |image/*| - | | processFile | 处理原始文件 | Function |function (file, next) { next(file) }| - |以上默认值均可在 src/components/upload/upload.vue 的 props 定义与 src/components/upload/btn-mixin.js 中逐一核对。v-model 双向同步valueprop 在 watch 中同步到内部files而内部files一旦变化即$emit(input, newFiles)见 src/components/upload/upload.vue从而形成完整双向绑定auto 与 pauseddata中paused: !this.auto即autofalse时组件默认处于暂停状态配合实例方法start()手动触发上传这正是官方 default 示例里「先选文件、点 Upload 按钮再传」的实现基础isShowBtn当files.length max时自动隐藏选择按钮v-showisShowBtn见 src/components/upload/upload.vue 与 L85-L87。5.1 action 子配置当action是字符串时组件会自动转换为{ target: action }见 src/components/upload/upload.vue 的actionOptions计算属性action为空字符串时返回null此时upload()直接返回不发起请求。| Attribute | Description | Type | Default | | - | - | - | - | | target | multipart POST 目标 URL若为函数则以 file object 为参数调用返回值作为 URL | String/Function1.11.0| - | | fileName | multipart POST 参数名 | String |file| | prop | 上传 file object 上的哪个属性 | String |file| | headers | 额外请求头若为函数则以 file object 为参数调用返回值作为 headers | Object/Function1.11.0|{}| | data | 额外表单数据若为函数则以 file object 为参数调用返回值作为 data | Object/Function1.11.0|{}| | withCredentials | 标准 CORS 请求默认不携带 cookie设为true后随请求发送 cookie | Boolean |false| | timeout | 上传请求超时时间 | Number |0| | progressInterval | 进度上报时间间隔单位ms | Number |100| | checkSuccess | 判断响应是否成功参数为(response, file[, cb])。file与可选cb自 1.11.0 起可用无cb时以函数返回值isSuccess作为结果有cb时调用cb(isSuccess)。isSuccess为true时视为上传成功 | Function |function (res) { return true }|底层实现对照src/components/upload/ajax.jsajaxUpload(file, options, changeHandler)是实际发请求的函数逐项印证上述配置target、headers、data均通过evalOpts求值——若配置为函数则用 file object 调用否则原样返回见 src/components/upload/util.js。例如可按「每个文件带自己的签名」动态生成 headers请求体为FormData先 appenddata中的各字段再formData.append(fileName, file[prop])见 ajax.js L55-L60。prop默认为file即上传原始文件改为base64Value即上传 base64 字符串进度上报节流xhr.upload.onprogress中按progressInterval控制更新频率file.progress e.loaded / e.total见 ajax.js L29-L53超时仅当timeout 0时设置xhr.timeoutontimeout与onerror一样走失败分支见 ajax.js L84-L87、L97-L99withCredentials为true时设置xhr.withCredentials true见 ajax.js L90-L92checkSuccess的两种形态源码按checkSuccess.length 2区分——参数个数 ≤2无cb时直接取返回值否则调用cb(isSuccess)异步判定见 ajax.js L70-L78。这解释了文档中「无 cb 则函数返回值即结果有 cb 则回调决定」的约定状态机终点onload中先校验 HTTP 状态码 200 || 300直接失败再setResponse()并依据checkSuccess结果将file.status置为success或errorsetStatus会清空进度定时器、将file.progress置为1并回调changeHandler通知组件触发file-success/file-error事件见 ajax.js L62-L108事件分发见 src/components/upload/upload.vue。5.2 processFile 子配置processFile是一个(file, next)形式的函数file是原始文件处理完成后必须调用next并传入处理后的文件。若未配置使用默认实现function (file, cb) { cb(file) }见 src/components/upload/upload.vue即原样放行。6. 事件一览| Event Name | Description | Parameters | | - | - | - | | files-added | 文件被加入时触发通常用于文件校验 | 原始文件列表 | | file-submitted | 文件被加入upload.files时触发 | file object | | file-removed | 文件被移除时触发 | file object | | file-success | 文件上传成功时触发 | file object | | file-error | 文件上传失败时触发 | file object | | file-click | 文件被点击时触发1.12.39 起追加index参数 | file objectindex| | input | 绑定值文件列表变化时触发 | 更新后的文件列表 |事件名称在源码中以常量集中定义见 src/components/upload/upload.vuefiles-added、file-submitted、file-removed、file-success、file-error、file-click与input。几点源码层面的补充file-click由cube-upload-file的点击冒泡而来index参数是v-for循环的下标见 src/components/upload/upload.vuefile-removed在removeFile方法开头即触发先于请求中断与 DOM 移除可用于埋点或提示单个文件结束无论成败都会回调upload(retry)继续推进队列见 src/components/upload/upload.vue因此simultaneousUploads控制的是「在飞请求数」uploading状态的文件会计入并发数直到其结束才会补位下一个ready文件。7. 实例方法| Method name | Description | Parameter | | - | - | - | | start | 开始上传 | - | | pause | 暂停上传 | - | | retry | 重试上传 | - | | removeFile | 移除文件 | file object |对应实现src/components/upload/upload.vuestart()paused false后调用upload()开始/继续上传pause()置paused true并遍历files对uploading状态的文件执行file._xhr.abort()且状态回退为readyretry()生成新的retryIdDate.now()解除暂停并以upload(true)重试重试时仅对error状态且_retryId ! this.retryId的文件重新发起请求见 upload.vue L146保证同一轮重试中每个失败文件只重试一次removeFile(file)如 4.2 节所述负责中断请求、释放 ObjectURL、删除并推进队列。8. 组件注册与按需引入cube-upload及其子组件cube-upload-btn、cube-upload-file通过 src/modules/upload/index.js 统一注册install中注册三个组件同时把子组件挂到Upload.Btn/Upload.File上。使用方式以全量引入为例import Vue from vue import CubeUpload from cube-ui Vue.use(CubeUpload)或在需要时按需引入该模块与官方推荐的方式保持一致。组件的源码、样式与按需打包产物分别位于 src/components/upload/、src/components/upload/upload.vue 与 lib/upload/含upload.min.js、upload.min.css与index.js。9. 进阶实践建议结合文档与源码汇总几条可直接落地的实践经验文件校验的最佳时机files-added是唯一的同步校验入口务必在此回调中修改file.ignore支持按file.size、file.type、文件数量等条件过滤校验提示可使用$createToast并发与顺序控制simultaneous-uploads从 1 到 N 可平滑调节「同时上传数」配合autofalsestart()可实现「先选后传」上传大图/多图时建议限制并发避免移动端卡顿Base64 上传的完整链路processFile中调用压缩插件并next(处理后的文件)→file-submitted中把file.file.base64搬运到 file object 的自定义字段 →action.prop指向该字段。三者缺一不可任一环节遗漏都会导致服务端收到空字段或原始文件内存管理组件在removeFile中自动URL.revokeObjectURL日常使用无需手动清理但若业务上长时间保留文件列表可关注url字段的释放时机自定义校验响应服务端返回 JSON 时利用checkSuccess依据业务字段如res.code 0判定成败并可从file.response提取错误信息展示在file-error回调中。以上内容均可在文档 document/components/docs/en-US/upload.md 与仓库源码src/components/upload/、src/modules/upload/index.js、示例 example/pages/upload/中交叉验证读者可依此深入研读或二次开发。赞分享前端UI组件移动开发【免费下载链接】cube-ui:large_orange_diamond: A fantastic mobile ui lib implement by Vue项目地址https://gitcode.com/gh_mirrors/cu/cube-ui点击查看免费下载相关推荐cube-ui Upload 组件实战文件对象模型、并发上传、图片压缩与自定义结构cube ui Upload 组件实战文件对象模型、并发上传、图片压缩与自定义结构 cube ui 是滴滴出行团队开源、基于 Vue.js 的移动端 UI 组前端UI组件移动开发G-Helper终极指南华硕游戏本性能优化与色彩恢复完整教程G Helper终极指南华硕游戏本性能优化与色彩恢复完整教程 你是否厌倦了Armoury Crate的臃肿和卡顿是否遇到过ROG游戏本屏幕突然发白、色彩失真桌面应用系统编程cube-ui Toast 组件完全指南$createToast 非模态提示的配置、事件与源码剖析cube ui Toast 组件完全指南$createToast 非模态提示的配置、事件与源码剖析 cube ui 是滴滴开源的移动端 Vue 组件库其 T前端UI组件移动开发上一篇探索Monika After Story与虚拟伴侣建立深度连接的终极指南下一篇Office界面定制神器用Office Custom UI Editor打造高效个性化工作区创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表