n-upload 文件上传
九宫格图片 / 视频列表:选择(相册 / 拍摄,数量 / 大小 / 扩展名校验)→ 上传 → 地址回填 → 点击预览 → 删除。
- 上传双模式:
action非空 = 自动模式(选完即调 uni.uploadFile,name/header/formData透传,进度百分比 + 进度条、失败重试 UI 内置;auto-upload=false改为选完入列、ref 统一触发);action空串 = 手动模式(afterRead交业务上传,经 ref 的setProgress/result/fail回报进度与结果)- 地址回填双通道:自动模式 HTTP 成功后按「
data字符串直取 → 顶层url→data.url」自动解析返回体,命中即零配置回填;未命中(或手动模式)由业务在 success / afterRead 里调result(url, index)显式回填——未回填的文件不进入 modelValuemodelValue恒为string[](已回填地址的文件列表);头像等单文件场景传max-count=1后取首项;外部赋值即重置初始列表- 校验内建:
max-count数量、max-size单文件大小(MB)、extension扩展名白名单;被拒文件派发exceed/oversize事件并轻提示(文案多语言)- 图片点击走系统全屏预览(
preview可关);视频无平台缩略图,深底图标 + 播放角标呈现,点击只派发preview事件由业务接管播放
平台兼容性
| App | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ小程序 |
|---|---|---|---|---|---|---|
| √ | √ | √ | × | × | × | × |
API
属性
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|---|---|---|---|---|
| model-value | 已回填地址的文件列表(string[],配合 @update:model-value 双向绑定);上传回填 / 删除时更新,外部赋值即重置初始列表 | Array | [] | - |
| action | 上传接口地址;空串 = 手动模式(afterRead 交业务上传,经 ref 回报结果),非空 = 自动调 uni.uploadFile | String | "" | - |
| name | 上传接口的文件字段名(uni.uploadFile 的 name 参数) | String | "file" | - |
| header | 上传接口的请求头(如鉴权 token) | Object | null | - |
| form-data | 上传接口附带的表单数据 | Object | null | - |
| accept | 媒体类型:image 图片(可多选)/ video 视频(单选) | String | image | image / video |
| max-count | 最大文件数;0 / -1 不限(单次选择仍封顶 9,平台限制);达到上限隐藏加号格 | Number | 9 | - |
| max-size | 单文件大小上限(MB);0 不限;超限文件被拒并派发 oversize + 轻提示 | Number | 0 | - |
| extension | 允许的扩展名白名单(按文件路径后缀匹配,不区分大小写);空数组不限;不匹配的文件被拒并轻提示 | Array | [] | - |
| size-type | 图片压缩方式(uni.chooseImage 的 sizeType):original 原图 / compressed 压缩图 | Array | ["original","compressed"] | - |
| source-type | 选择来源:album 相册 / camera 拍摄 | Array | ["album","camera"] | - |
| compressed | 是否压缩所选视频(仅 accept="video" 生效) | Boolean | true | - |
| camera | 拍摄视频的摄像头(仅 accept="video" 且 sourceType 含 camera 时生效) | String | back | back / front |
| max-duration | 拍摄视频最长时长秒(仅 accept="video" 生效) | Number | 60 | - |
| auto-upload | 自动模式下选完即传;false = 选完仅入列(待传态),经 ref.upload() 统一触发 | Boolean | true | - |
| use-before-read | 选择文件返回后先派发 beforeRead,由业务 callback 决定是否继续校验入列(异步前置拦截:查重 / 鉴权 / 内容审核等内建校验覆盖不了的场景) | Boolean | false | - |
| disabled | 禁用:拦截选择与删除(保色相降透明),已选文件仍可预览 | Boolean | false | - |
| deletable | 显示每格右上角删除按钮;false = 只能看不能删 | Boolean | true | - |
| confirm-delete | 删除前弹系统确认框(文案走多语言) | Boolean | false | - |
| preview | 点击已选图片调用系统全屏预览(预览范围为列表内全部图片;视频恒走 preview 事件由业务接管) | Boolean | true | - |
| preview-image | 展示列表内缩略图;关闭时数据、校验和上传保留,独立于 preview 全屏预览 | Boolean | true | - |
| show-progress | 上传中显示进度百分比 + 进度条;false 显示加载圈 | Boolean | true | - |
| width | 格子宽度:数值 px 或任意 css 长度("30%" 等) | String / Number | 80 | - |
| height | 格子高度:数值 px 或任意 css 长度 | String / Number | 80 | - |
| radius | 格子圆角:数值 px 或任意 css 长度;空串取主题令牌(--n-upload-radius,默认 8px) | String / Number | "" | - |
| gutter | 格子间距(px,作用于每格右侧与下侧) | Number | 8 | - |
| image-mode | 已选文件的缩放模式(image 原生 mode 子集):aspectFill 短边铺满居中裁剪 / aspectFit 完整显示留白 / scaleToFill 拉伸铺满 | String | aspectFill | aspectFill / aspectFit / scaleToFill |
| upload-icon | 加号格图标名(n-icon 名称表) | String | plus | - |
| upload-text | 加号格图标下方的说明文字(如 "上传照片");空串不显示 | String | "" | - |
| upload-icon-color | 加号格图标颜色(任意 CSS 色值);空串取次要文字色(随主题) | String | "" | 与 css 相同 |
| custom-class | 挂到根节点的额外 class(类需定义在组件样式表内) | String | "" | - |
| custom-style | 根节点行内样式 | String | "" | 与 css 相同 |
事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:model-value | 已回填地址的文件列表变化(v-model 通道) | urls: string[] |
| change | 与 update:modelValue 同参同发 | urls: string[] |
| before-read | 选择返回后、校验入列前触发(use-before-read 开启时);callback(false) 丢弃本次选择(提示业务自理) | { files, callback }(files: NUploadFileItem[],index 恒 -1 = 尚未入列;callback: (ok: boolean) => void,异步回执有效) |
| after-read | 新选文件全部通过校验并入列后触发(手动上传模式由此接管) | files: NUploadFileItem[](index / path / size / name / duration) |
| success | 单个文件上传完成(自动模式 = HTTP 成功;手动模式 = result() 回填) | { index, url, filePath, response }(url 为自动解析结果,未命中为空串;response 为返回体原文,手动模式为空串) |
| error | 单个文件上传失败(选择器调用失败 index 为 -1;用户取消选择不派发) | { index, filePath, errMsg } |
| progress | 上传进度更新 | { index, progress }(0-100) |
| exceed | 选择数量超出 max-count 被拒 | files: NUploadFileItem[](被拒部分) |
| oversize | 文件超过 max-size 被拒 | files: NUploadFileItem[](被拒部分) |
| delete | 删除文件后触发 | { index, url }(url 为已回填地址,未回填为空串) |
| preview | 点击文件时触发(图片默认同时调系统全屏预览;失败态点击走重试不派发);视频由此接管播放 | { index, url } |
方法(ref 直调)
实例通过 ref 直接调用下列公开方法;组件专属实例类型须通过目标 Android 编译验证:
| 方法 | 说明 | 参数 |
|---|---|---|
| choose | 选择文件;-1 新增、有效下标替换;取消、失败或校验不通过保留旧项;禁用/目标上传中拦截 | (index: number = -1) |
| upload | 触发上传全部待传 / 失败文件(action 非空时有效;失败项一并重试) | 无 |
| result | 回填上传结果:url 就位即 success 并计入 modelValue(重复回填同值不重复派发) | (url: string, index: number) |
| fail | 手动上传回报失败:对应格转入失败态(自动模式有 action 时点格即可重试) | (index: number) |
| setProgress | 手动上传回报进度:对应格转入上传中并显示进度,与自动模式同派 progress 事件 | (progress: number, index: number) |
插槽
| 插槽名 | 说明 |
|---|---|
| add | 自定义加号格内容(默认渲染 n-icon 图标 + 可选文字) |
实现说明
选择与呈现机制对照
| 机制 | 参考做法 | 本组件选择与理由 |
|---|---|---|
| 外部入口 | 实例方法选择文件 | choose(index=-1) 公开同一选择管线;-1 新增,已有下标替换;仍执行数量、类型和大小校验。 |
| 替换 | 选择成功后替换指定项 | 校验通过才替换,取消或失败保留旧文件;稳定 uid 防止列表变动后写错位置。 |
| 缩略图 | 列表展示与全屏预览分开开关 | previewImage 只控制媒体缩略图,文件格、进度、错误、重试和删除保持可用;preview 控制点击后的全屏预览。 |
- 机制对照(参考做法 vs 本库做法):
- 值模型:参考源取 string / string[] 双形态(随 multiple 切换)或 fileList 内部态 + urls 双轨。本库统一
modelValue: string[](已回填地址),单文件场景由 max-count=1 表达——与 n-picker 全模式 string[] 的库内惯例一致,避免"同名 prop 改变值类型"的隐式契约;multiple prop 不收(max-count=1 即单选,语义被全覆盖)。 - 地址解析:参考源要么绑自家后端格式、要么全靠业务在 success 里回填。本库取两层:常见返回体(
data直串 /url/data.url)自动解析零配置回填,未命中走 ref.result() 显式回填(业务回填通道全保留),两种格式都完整进入 modelValue。 - 上传编排:手动 / 自动双模式 + auto-upload 开关 + ref.upload() 批量触发 + 失败点格重试,取各参考源并集;删除在上传中拦截(轻提示),删除前可选系统确认。
- 进度视觉:百分比文字 + 底部细进度条(show-progress 关闭换加载圈);不依赖 n-progress(未交付组件),条宽由行内样式驱动。
- 视频呈现:uni-app x 的 chooseVideo 不返回缩略图(GetVideoInfo 才有),深底 + 视频图标 + 播放角标占位,点击只派发 preview 事件由业务接管播放;图片点击走系统全屏预览(预览列表 = 列表内全部图片,本地临时路径与已回填地址均可)。
- 点击已选项替换(少数参考源的交互)不收:与"点图预览"手势冲突,误触率高,从使用者视角择预览。
- 值模型:参考源取 string / string[] 双形态(随 multiple 切换)或 fileList 内部态 + urls 双轨。本库统一
- 参考并集缺口裁决(cl / un / fui / 旧库四源实读对照,逐项取舍):
- useBeforeRead + beforeRead 收编:选择返回后、内建校验前的异步前置拦截(查重 / 鉴权 / 内容审核)——此前业务无法在入列前拒收文件,为真实能力缺口;回执 callback(ok) 与参考源同构,index 恒 -1(尚未入列,与选择器失败载荷同语义)。
- multiple 不收(cl / un 均有):max-count=1 即单选,值模型恒 string[] 不随开关变形,语义被全覆盖。
- capture 不收(un 有):与 sourceType 同义(album / camera 拾取模式),本库命名与平台 API 参数一致。
- compressImage / compressOptions 不收(un 有):图片深度压缩参数跨端实现差异大(H5 走 canvas 且有压缩后上传丢原文件名的已知缺陷,官方文档自载),平台原生开关(sizeType / compressed)已收录,深度压缩由业务在 afterRead 拿到路径后自理。
- round 不收(un 有):radius 全覆盖("50%" / 999px 即圆),不设同义快捷 prop。
- bgColor 不收(un easycom 有、其文档 API 表未载):加号格底色定制——#add 插槽内容铺满格子即可自带底色,观感统一优先走主题令牌。
- accept="file" 不收(un 有):平台 API 缺失——uni.chooseFile 仅 H5 可用、App 端无官方文件选择 API、微信端为 chooseMessageFile(聊天文件,语义不同),无法跨端收编。
- #file 逐格作用域插槽不收(un 有):逐格全接管会绕开内置状态机(进度 / 失败重试 / 删除角标),组件核心价值即状态机;需要完全自定义展示的业务用 #add + afterRead 自管列表。
- fileList 状态预设(uploading / reload / error 初始态,un 有)不收:值模型统一受控单轨(modelValue: string[],外部赋值即全部按已完成渲染);编辑场景回显失败态可由业务对初始项调 fail() / setProgress() 置态。
- isAdd / addSize / borderColor / borderStyle 不收(fui 有):纯展示已有列表归 n-image / n-album 组件族;加号图标尺寸与边框样式经 #add 插槽全量接管,观感统一走主题令牌。
- 状态机:每文件 pending(纯图可见)→ uploading(深色遮罩 + 进度)→ success(透明覆盖层)/ error(警示 + 重新上传,点格重试)。覆盖层常驻铺满、按「状态 + 删除钮 / 重试钮 / 进度形态」装配 key 整层销毁重建(App 端子节点插拔不重绘铁律);进度数值不入 key,同状态内仅行内宽度更新。
- 下标稳定性:上传闭包持有文件对象引用、按 uid 重定位下标——上传中删除其它文件导致列表偏移不会错写;事件与 ref 方法携带的下标以调用时刻的实际位置为准。
- 校验与反馈:数量 / 大小 / 扩展名逐项校验,被拒文件按原因分组派发(exceed / oversize)并按首个命中原因轻提示(文案走多语言);扩展名不匹配仅轻提示(不设独立事件,参考源同款处理)。用户取消选择不派发 error。
- 外部赋值语义:modelValue 与当前已回填列表比对,不同即整表重建(初始 / 重置),进行中的上传项被丢弃(受控重置语义);组件卸载后网络回调静默丢弃,不再派发事件。
- 主题令牌:
--n-upload-radius(格子圆角)、--n-upload-mask-color(上传中 / 失败遮罩)、--n-upload-video-bg/--n-upload-play-bg(视频占位)、--n-upload-bar-height/--n-upload-bar-track(进度条)、--n-upload-del-size/--n-upload-del-bg(删除钮)、--n-upload-disabled-opacity(禁用透明)、--n-upload-text-size(加号文字);进度条填充色取品牌色令牌随主题。加号格图标尺寸为常量(与 $n-upload-icon-size 令牌默认值联动,见 variable.scss 注释)。