☰
uv-upload 上传组件完全指南:基于 uv-ui 的多端文件选择、参数配置与源码级上传流程解析
2026/10/15 6:38:30 网站建设 项目流程
  • 前端
  • UI组件
  • 跨平台

【免费下载链接】uv-ui

uv-ui 破釜沉舟之兼容vue3+2、app、h5、小程序等多端基于uni-app和uView2.x的生态框架,支持单独导入,开箱即用,利剑出击。

项目地址:https://gitcode.com/gh_mirrors/uv/uv-ui
点击查看免费下载

导读

本文围绕 uv-ui 生态中的uv-upload 上传组件展开,系统讲解其在 uni-app 多端项目中处理图片、视频与文件选择的完整方案。你将掌握该组件的全部 props 参数与事件回调的用法,理解「选择文件 → 读取前校验 → 大小检查 → 上传回调 → 删除与预览」的底层工作链路,并学会结合仓库示例快速落地一个带上传状态、进度反馈与预览能力的功能页面。

一、组件定位与适用场景

uv-upload是 uv-ui 中用于「上传图片等文件场景」的核心组件(见 组件说明文档)。它本身不负责真正的网络上传——实际的文件传输仍由开发者基于uni.uploadFile完成,组件负责的是更繁琐的前半段工作:

  • 调用各平台的文件选择能力(相册、摄像头、聊天文件等);
  • 对选中文件做类型格式化、数量与大小校验;
  • 渲染缩略图网格、上传中遮罩、失败提示、删除按钮与成功角标;
  • 提供图片全屏预览与视频弹层预览。

从 components.config.js 可以看到,uv-ui 官方示例将其归类于「表单组件」组,示例页面位于 upload.nvue。组件源码主体在 uv-upload.vue,共依赖uv-ui-tools、uv-icon、uv-loading-icon、uv-popup四个模块(见 package.json)。

二、快速上手:基础用法

组件支持easycom 规范,在 uni-app 项目中无需手动注册,模板中直接使用即可:

<template> <uv-upload :fileList="fileList" @afterRead="afterRead" @delete="deletePic" name="1" multiple :maxCount="10" ></uv-upload> </template> <script> export default { data() { return { fileList: [] } }, methods: { // 删除图片 deletePic(event) { this.fileList = this.fileList.filter((item, index) => { return index != event.index }) }, // 新增图片 async afterRead(event) { // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式 let lists = [].concat(event.file) let fileListLen = this.fileList.length lists.map((item) => { this.fileList.push({ ...item, status: 'uploading', message: '上传中' }) }) // 此写法可以避免使用老写法在 VUE3 中不更新 // #ifdef VUE3 this.fileList = this.fileList.filter((item, index) => { return index >= 0 }) // #endif for (let i = 0; i < lists.length; i++) { const result = await this.uploadFilePromise(lists[i].url) let item = this.fileList[fileListLen] this.fileList.splice(fileListLen, 1, Object.assign(item, { status: 'success', message: '', url: result })) fileListLen++ } }, uploadFilePromise(url) { return new Promise((resolve, reject) => { let a = uni.uploadFile({ url: 'http://www.example.com/upload', // 仅为示例,非真实的接口地址 filePath: url, name: 'file', formData: { user: 'test' }, success: (res) => { setTimeout(() => { resolve(res.data.data) }, 1000) } }); }) } } } </script>

关键约定:双向数据流由你维护

组件是纯展示 + 事件驱动的,fileList并不被组件内部直接修改:

  • 选择文件后组件只派发afterRead事件,你必须在回调中把新文件追加进自己的fileList;
  • 点击删除只派发delete事件并携带index,由你在回调中从fileList里移除对应项。

组件通过watch深度监听fileList(见 uv-upload.vue),变化后自动调formatFileList()重算缩略图网格与剩余可选数量。示例中把列表先标记为status: 'uploading', message: '上传中',上传完成后替换为status: 'success',正是为了驱动组件渲染状态遮罩。

三、参数配置全解析

所有参数定义在 props.js,并可通过uni.$uv.props.upload做全局默认配置覆盖。完整参数表如下:

参数类型默认值说明
acceptString'image'接受的文件类型,可选all/media/image/file/video
captureString | Array['album', 'camera']图片或视频拾取模式;accept为 image 时,追加camera可允许直接调起摄像头
compressedBooleantrueaccept为 video 时生效,是否压缩视频
cameraString'back'accept为 video 时生效,可选back或front
maxDurationNumber60accept为 video 时生效,拍摄视频最长时长(秒)
uploadIconString'camera-fill'上传区域的图标,只能使用内置图标
uploadIconColorString'#D3D4D6'上传区域图标的颜色
useBeforeReadBooleanfalse是否开启「文件读取前事件」模式
afterReadFunctionnull读取后的处理函数(等价于afterRead事件)
beforeReadFunctionnull读取前的处理函数(等价于beforeRead事件)
previewFullImageBooleantrue是否开启图片预览功能
previewFullVideoBooleantrue是否开启视频预览功能
maxCountString | Number52最大上传数量
disabledBooleanfalse是否禁用组件
imageModeString'aspectFill'预览图的裁剪模式,与<image>的mode属性一致
nameString''标识符,可在回调函数的第二项参数中获取
sizeTypeArray['original', 'compressed']所选图片的尺寸,可选original/compressed
multipleBooleanfalse是否开启图片多选(部分安卓机型不支持)
deletableBooleantrue是否展示删除按钮
maxSizeString | NumberNumber.MAX_VALUE文件大小限制,单位为 byte
fileListArray[]已上传文件列表
uploadTextString''上传区域的提示文字
widthString | Number80预览区域与选择按钮区域宽度
heightString | Number80预览区域与选择按钮区域高度
previewImageBooleantrue是否在上传完成后展示预览图
customStyleObject-组件自定义样式,内部经$uv.addStyle合并

几个需要留意的参数行为

  • maxCount默认 52:组件通过isInCount = lists.length < maxCount控制「+」按钮是否继续显示;传入 52 是给微信小程序chooseMedia等接口的上限兜底留出的余量(uv-upload.vue)。
  • multiple与maxCount的组合:选择器内部对单次选择数量做了二次收敛,图片/媒体接口单次最多min(maxCount, 9),文件接口为multiple ? maxCount : 1(见 utils.js)。
  • maxSize单位是字节:例如限制 2MB 应传2 * 1024 * 1024。
  • deletable支持逐项覆盖:fileList中每个 item 可携带布尔型deletable字段,优先级高于组件级配置(uv-upload.vue);changelog 中 1.0.6 版本专门修复了「动态设置deletable为 false 不生效」的问题。

四、事件与回调

组件在 uv-upload.vue 中声明了 6 个事件:

事件触发时机回调参数要点
error文件选择失败(用户取消、系统异常等)底层选择接口的错误对象
beforeRead文件读取前(需开启useBeforeRead){ file, name, index, callback },callback(ok)可异步放行/拦截
oversize文件超出maxSize限制{ file, name, index }
afterRead文件读取后{ file, name, index };multiple时file为数组
delete点击删除按钮{ file, name, index }
clickPreview点击预览(图片或视频均触发)文件 item 与{ name, index }

三种拦截/校验姿势

从源码onBeforeRead/onAfterRead(uv-upload.vue)可以看到组件提供的校验链路:

  1. beforeRead函数:返回false则中断;返回 Promise 则等待其 resolve 后继续;
  2. useBeforeRead事件模式:组件会把callback一并传入事件,业务侧异步调用callback(false)即可拦截该文件;
  3. oversize事件:文件大小超过maxSize时触发并终止本次读取流程,不会进入afterRead。

三者可按需组合,例如先拦截非图片文件,再在oversize中提示「文件过大」。

五、实战案例:六种典型用法

官方示例页 upload.nvue 提供了可直接对照的完整代码,这里提炼其核心配置:

场景关键配置
基础用法:fileList="fileList1"+multiple+:maxCount="10"
上传视频accept="video",选择走uni.chooseVideo
文件预览:previewFullImage="true",点击缩略图全屏预览
隐藏上传按钮当fileList长度达到maxCount时按钮自动消失(如:maxCount="2")
限制上传数量:maxCount="3",超出后不再显示「+」按钮
自定义上传样式width="250"height="150"+ 默认插槽内放置自定义<image>,此时仍保留全部选择、上传与删除逻辑

示例页通过name="1"~name="6"区分六组互不干扰的文件列表,并在回调中借助event.name定位目标数组,这一「多实例区分」技巧在多表单场景下非常实用。

六、上传链路源码级解析

组件把「选择 → 读取 → 校验 → 展示 → 删除/预览」拆成了清晰的方法链,整体流程如下:

用户点击上传区 │ ▼ chooseFile() // 按 accept 分发到平台选择接口 │ Promise resolve ▼ onBeforeRead(file) // beforeRead 函数 / useBeforeRead 事件(可拦截) │ ▼ onAfterRead(file) // 检查 maxSize → 触发 oversize 或 afterRead │ ▼ 业务侧 afterRead 回调 // 开发者调用 uni.uploadFile 真正上传 │ ▼ 更新 fileList 的 status // uploading → success / failed,组件 watch 重绘

选择器分发逻辑

核心实现在 utils.js 的chooseFile(),按accept走不同底层 API:

accept底层 API平台限制
imageuni.chooseImage全端
mediawx.chooseMedia仅微信小程序
videouni.chooseVideo全端
filewx.chooseMessageFile(微信)/uni.chooseFile(H5)仅微信小程序与 H5,且 H5 需 HBuilderX 2.9.9+
其他(保底)按all类型选取全部文件同上

各分支还会把原生返回结果统一格式化为{ url, thumb, size, type, name }结构的标准文件对象(formatImage/formatVideo/formatMedia/formatFile),这正是afterRead回调里event.file的数据来源。

类型识别与状态渲染

  • 组件在formatFileList()中通过accept或 URL 后缀判断isImage/isVideo(uv-upload.vue);
  • 底层正则来自 test.js:图片匹配jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg,视频匹配mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8,因此本地 blob 地址无法识别类型时,会优先以accept判断;
  • 渲染层依据item.status显示三种状态:uploading(旋转 loading)、failed(叉号 + message)、success(右下角对勾角标)。其中成功角标在 APP-NVUE 下使用内置 base64 图片,其余平台用 CSS 绘制三角形,源码注释中明确说明了这一平台差异(uv-upload.vue)。

预览能力

  • 图片:调用uni.previewImage,并先过滤出所有图片项、以当前点击项作为current起始位置(uv-upload.vue);
  • 视频:交给内置的 uv-preview-video.vue,通过uv-popup弹层承载<video>并默认自动播放。

七、accept 的平台约束(重要)

不同accept值对运行平台有硬性要求,组件通过 mixin.js 在accept变化时主动error提示:

  • 非微信小程序平台:不允许配置all或media;
  • 非微信小程序且非 H5 平台:不允许配置file。

也就是说,file与media类型具有较强的平台排他性。建议在跨端项目中按条件分支配置accept(例如#ifdef MP-WEIXIN下才启用file),并在oversize/error回调中做降级处理。组件在 package.json 中声明的兼容矩阵覆盖 Vue2/Vue3、App(vue/nvue)、H5(PC 与移动端主流浏览器)以及微信、阿里、百度、字节跳动、QQ 等小程序端。

八、样式定制要点

组件样式基于 SCSS 变量体系(uv-upload.vue),常用可覆盖变量包括:

  • 预览格尺寸:$uv-upload-preview-border-radius、$uv-upload-preview-margin;
  • 按钮区:$uv-upload-button-bgColor、$uv-upload-button-border-radius、$uv-upload-hover-bgColor、$uv-upload-disabled-opacity;
  • 删除角标:$uv-upload-deletable-bgColor;
  • 状态遮罩:$uv-upload-status-bgColor(默认rgba(0, 0, 0, 0.5))。

此外uploadIcon/uploadText/width/height/customStyle以及默认插槽(自定义整个上传按钮区域)已覆盖绝大多数 UI 定制诉求,一般无需改动组件源码。

九、版本演进与已知修复

根据 changelog.md,组件自 1.0.0(2023-05-10)发布以来的关键演进如下:

  • 1.0.1:优化依赖,组件导入即可使用,无需全局引入;
  • 1.0.2:fileList的 watch 增加deep,深层字段变更也能正确重绘;
  • 1.0.3:去除插槽判断,规避部分平台显示异常;
  • 1.0.4:修复图片预览位置错误、视频预览不生效、视频宽高修改不生效;
  • 1.0.5:新增uv-popup依赖(视频预览弹层底层);
  • 1.0.6:修复动态设置deletable为 false 不生效。

这些修复记录对排查旧版本问题有直接参考价值:若你遇到预览定位偏差、视频弹层无法打开或删除按钮无法动态隐藏,可优先核对当前依赖版本是否 ≥ 对应修复版本。

结语

uv-upload的价值在于把「多端文件选择 + 校验 + 状态化缩略图 + 预览」这套极易踩平台差异的样板逻辑收敛进一个组件,而把「真正上传」的控制权完整交还开发者。基于本文的参数表、事件链与示例代码,你可以直接落地带上传进度、失败重试、数量/大小限制与自定义样式的能力页面;需要更细的边界行为时,可继续研读 uv-upload.vue、utils.js 与 upload.nvue 三份核心源码。

  • 前端
  • UI组件
  • 跨平台

【免费下载链接】uv-ui

uv-ui 破釜沉舟之兼容vue3+2、app、h5、小程序等多端基于uni-app和uView2.x的生态框架,支持单独导入,开箱即用,利剑出击。

项目地址:https://gitcode.com/gh_mirrors/uv/uv-ui
点击查看免费下载
上一篇:X-BUILD项目结构解析:理解大型Vue3应用的最佳组织方式
下一篇:Awesome Claude Skills插件开发实战:技能发布与推广完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询