更新记录

1.0.0(2026-07-16) 下载此版本

1.1.5(2026-07-16)

  • 上传:name / header / formData 合并为 uploadOptions,默认 { name:'file', header:{}, formData:{} },只填 uploadUrl 即可上传
  • 文档:readme.md 补全安装、快速上手、Props / Events / 方法 / 插槽 / 上传约定与完整示例

1.1.4(2026-07-16)

  • 上传:formData 完全由用户配置,不再自动注入 isCover / index;文档补充 uploadUrl / header / formData / name

1.1.3(2026-07-16)

  • 显示开关:showCover(角标+设封面)、showRemoveshowSize;文案 coverText / setCoverText

1.1.2(2026-07-16)

  • 恢复真正的长按拖拽排序:浮层跟手、占位高亮、拖动锁滚(@dragging + page-meta)

1.1.1(2026-07-16)

  • (已回退)曾改为点选放置

1.1.0(2026-07-16)

  • 增强:排序、封面、本地压缩与体积、上传进度条

1.0.0(2026-07-16)

  • 首发:九宫格选图、预览、删除、maxCount / maxSize、可选 autoUpload

1.1.5(2026-07-16)

  • 上传:name / header / formData 合并为 uploadOptions,默认 { name:'file', header:{}, formData:{} },只填 uploadUrl 即可上传
  • 文档:readme.md 补全安装、快速上手、Props / Events / 方法 / 插槽 / 上传约定与完整示例

1.1.4(2026-07-16)

  • 上传:formData 完全由用户配置,不再自动注入 isCover / index;文档补充 uploadUrl / header / formData / name

1.1.3(2026-07-16)

  • 显示开关:showCover(角标+设封面)、showRemoveshowSize;文案 coverText / setCoverText

1.1.2(2026-07-16)

  • 恢复真正的长按拖拽排序:浮层跟手、占位高亮、拖动锁滚(@dragging + page-meta)

1.1.1(2026-07-16)

  • (已回退)曾改为点选放置

1.1.0(2026-07-16)

  • 增强:排序、封面、本地压缩与体积、上传进度条

1.0.0(2026-07-16)

  • 首发:九宫格选图、预览、删除、maxCount / maxSize、可选 autoUpload

平台兼容性

uni-app(3.8.0)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟

kex-uploader

多图上传组件(uni-app Vue3):九宫格选图、长按拖拽排序、设封面、本地压缩、上传进度。

兼容 H5 / App / 各主流小程序。

功能一览

能力 说明
九宫格选图 uni.chooseImagev-modelstring[](url 数组)
预览 / 删除 点击预览,右上角删除
数量 / 大小限制 maxCountmaxSize(MB)
长按拖拽排序 浮层跟手;配合 page-meta 锁页面滚动
封面 首张为封面,非首张可点「设封面」
本地压缩 H5 canvas / 其它端 uni.compressImage,可调质量
自动上传 uni.uploadFile,最少只填 upload-url
上传进度 遮罩百分比 + 进度条,失败可点重试

安装

将本插件目录拷贝到业务项目:

项目根目录/uni_modules/kex-uploader/

uni-app easycom 会自动注册,无需手动 import

要求:uni-app Vue3。


快速上手

1. 仅选图(不上传)

<template>
  <kex-uploader v-model="images" :max-count="9" />
</template>

<script setup>
import { ref } from 'vue'
const images = ref([]) // string[],本地临时路径或远程 url
</script>

2. 自动上传(推荐)

最少只填接口地址,name / header / formData 有默认值:

<template>
  <kex-uploader
    v-model="images"
    :auto-upload="true"
    upload-url="https://example.com/api/upload"
    @uploadSuccess="onOk"
    @uploadFail="onFail"
  />
</template>

<script setup>
import { ref } from 'vue'
const images = ref([])

const onOk = (e) => {
  // e.url 优先取接口返回的远程地址;e.data 为解析后的 JSON
  console.log('上传成功', e.url, e.data)
}
const onFail = (e) => {
  console.log('上传失败', e.err)
}
</script>

3. 带 Token / 业务字段上传

<template>
  <kex-uploader
    v-model="images"
    :auto-upload="true"
    upload-url="https://example.com/api/upload"
    :upload-options="uploadOptions"
    @uploadSuccess="onOk"
  />
</template>

<script setup>
import { ref, computed } from 'vue'

const images = ref([])
const token = ref('Bearer xxx')

const uploadOptions = computed(() => ({
  // name 默认 'file',可不写
  header: {
    Authorization: token.value
  },
  // formData 的值必须是字符串
  formData: {
    folderId: '123',
    module: 'attachment'
  }
}))
</script>

4. 手动上传

<template>
  <kex-uploader
    ref="uploaderRef"
    v-model="images"
    :auto-upload="false"
    upload-url="https://example.com/api/upload"
    :upload-options="uploadOptions"
  />
  <button @click="doUpload">开始上传</button>
</template>

<script setup>
import { ref } from 'vue'

const images = ref([])
const uploaderRef = ref(null)
const uploadOptions = { header: { Authorization: 'Bearer xxx' } }

const doUpload = () => {
  uploaderRef.value?.uploadAll()
}
</script>

5. 排序 + 封面(含锁滚)

小程序 / App 拖动时建议配合 page-meta,避免页面跟着滚:

<template>
  <page-meta :disable-scroll="dragging" />

  <kex-uploader
    v-model="images"
    :sortable="true"
    :show-cover="true"
    @dragging="(v) => (dragging = v)"
    @sort="onSort"
    @coverChange="onCover"
  />
</template>

<script setup>
import { ref } from 'vue'

const images = ref([])
const dragging = ref(false)

const onSort = (e) => console.log('排序', e.from, '→', e.to)
const onCover = (e) => console.log('封面', e.url)
</script>

6. 本地压缩

<kex-uploader
  v-model="images"
  :compress="true"
  :compress-quality="0.7"
  :compress-max-width="1920"
  :show-size="true"
  @compress="onCompress"
/>
  • H5:canvas 压成 JPEG
  • App / 小程序:uni.compressImage
  • 开启后底部出现质量滑条(下次选图生效)
  • 角标显示:压缩后←原体积

7. 回显已有图片

<script setup>
import { ref } from 'vue'
const images = ref([
  'https://example.com/a.jpg',
  'https://example.com/b.jpg'
])
</script>

<template>
  <kex-uploader v-model="images" />
</template>

第一张即为封面(showCover 为 true 时显示角标)。


Props

属性 类型 默认值 说明
modelValue / v-model string[] [] 图片 url 列表;第 0 张为封面
maxCount Number 9 最多可选张数
maxSize Number 10 单张上限,单位 MB;0 表示不限制
sourceType string[] ['album','camera'] 选图来源
sizeType string[] ['original'] 传给 chooseImage;开启 compress 时内部会强制 original
disabled Boolean false 禁用(不可选、不可删、不可拖)
preview Boolean true 点击格子预览大图
showCount Boolean true 加号格显示「当前/上限」
size Number 160 格子边长,单位 rpx
toast Boolean true 超限、压缩等场景是否 toast
sortable Boolean true 长按拖拽排序
showCover Boolean true 封面角标 + 非首张「设封面」按钮
coverText String '封面' 首张角标文案
setCoverText String '封面' 设封面按钮文案
showRemove Boolean true 是否显示删除按钮
deletable Boolean true 兼容旧属性;与 showRemove 任一为 false 则不显示删除
showSize Boolean true 是否显示体积角标
compress Boolean false 选图后本地压缩
compressQuality Number 0.7 压缩质量 0.2 ~ 1
compressMaxWidth Number 1920 H5 压缩最大边长(px)
autoUpload Boolean false 选图(及压缩)完成后是否自动上传
uploadUrl String '' 上传接口;有值且 autoUpload 为 true 时自动上传
uploadOptions Object 见下表 上传参数,对应 uni.uploadFile

uploadOptions

字段 类型 默认 对应 uni.uploadFile 说明
name String 'file' name 文件字段名
header Object {} header 请求头,可用 computed 动态带 Token
formData Object {} formData 额外表单字段;值必须是字符串

未传的字段会自动补默认值,因此只配 upload-url 即可发起上传

// 完整示例
{
  name: 'file',
  header: { Authorization: 'Bearer xxx' },
  formData: { bizId: '1', type: 'image' }
}

Events

事件 触发时机 回调参数
update:modelValue 列表变化 string[] urls
change 列表任意变化 { urls, fileList, cover, ... }
select 每次选图完成(含压缩后) 见下方
uploadSuccess 单张上传成功 见下方
uploadFail 单张上传失败 { index, url, err, statusCode?, data?, res? }
sort 拖拽排序结束 { from, to, urls }
coverChange 封面变更 { url }
compress 单张压缩完成 { from, to, originSize, size, quality }
oversize 单张超体积 { path, size, maxSize }
exceed 超过 maxCount { maxCount }
remove 删除一张 { index, url }
dragging 拖动开始/结束 true / false

@select

{
  tempFilePaths, // string[] 本次新增路径(压缩后)
  files,         // 本次新增详情:{ url, localPath, byteSize, originSize, status, index }[]
  count,         // 本次新增张数
  urls,          // 当前全部 urls(同 v-model)
  fileList,      // 当前全部:{ url, status, byteSize, originSize, isCover }[]
  cover          // 封面 url
}

@uploadSuccess

{
  index,         // 在列表中的下标
  url,           // 优先为接口返回的远程 url,解析不到则仍为本地路径
  localPath,     // 上传时的本地路径
  isCover,       // 是否封面(index === 0)
  statusCode,    // HTTP 状态码
  data,          // 解析后的服务端 JSON(解析失败则为原始字符串)
  res,           // uni.uploadFile 原始 success 参数
  file,          // { url, localPath, byteSize, originSize, status }
  urls,          // 当前全部 urls
  fileList       // 当前全部文件详情
}

@change

{
  urls,      // string[]
  fileList,  // { url, status, progress, message, byteSize, originSize, isCover }[]
  cover      // 封面 url
}

文件 status 可能值:pending · compressing · uploading · success · fail


方法(ref)

<kex-uploader ref="uploaderRef" v-model="images" upload-url="..." />
方法 说明
choose() 打开选图
upload(index) 上传指定下标
uploadAll() 上传所有 pending / fail
setCover(index) 将第 index 张设为封面(移到首位)
moveItem(from, to) 移动位置
getFileList() 返回当前文件详情数组
getCover() 返回封面 url
uploaderRef.value.choose()
uploaderRef.value.uploadAll()
console.log(uploaderRef.value.getFileList())
console.log(uploaderRef.value.getCover())

插槽

插槽 说明
add 自定义「添加」格子内容
<kex-uploader v-model="images">
  <template #add>
    <text>添加图片</text>
  </template>
</kex-uploader>

上传接口约定

组件通过 uni.uploadFile 上传。HTTP 2xx 视为成功。

成功后会尝试从响应里解析远程地址,并写回 v-model。识别字段顺序:

  1. 字符串本身
  2. url / path
  3. data.url / data.path
  4. result.url / result.path

示例响应:

{ "code": 0, "data": { "url": "https://cdn.example.com/a.jpg" } }

若字段名不同,可在 @uploadSuccess 里用 e.data 自行处理,再改 v-model


注意事项

  1. Vue3 only,依赖 easycom / uni_modules
  2. formData 值必须是字符串(uni 规范),例如 folderId: '123',不要传数字或对象。
  3. 拖拽锁滚:H5 组件内会锁 body;小程序 / App 请监听 @dragging,配合页面
    <page-meta :disable-scroll="dragging" />
  4. 自动上传条件autoUpload === trueuploadUrl 非空。
  5. 封面:始终是列表第 0 张;拖到首位或点「设封面」都会触发 @coverChange
  6. 权限:选图会触发系统相册 / 相机授权,请在各端 manifest 中按需配置。

完整示例

<template>
  <page-meta :disable-scroll="dragging" />

  <view class="page">
    <kex-uploader
      ref="uploaderRef"
      v-model="images"
      :max-count="9"
      :max-size="10"
      :sortable="true"
      :show-cover="true"
      :show-remove="true"
      :show-size="true"
      :compress="true"
      :compress-quality="0.7"
      :auto-upload="true"
      upload-url="https://example.com/api/upload"
      :upload-options="uploadOptions"
      @select=""
      @change="onChange"
      @uploadSuccess="onUploadOk"
      @uploadFail="onUploadFail"
      @sort="onSort"
      @coverChange="onCover"
      @dragging="(v) => (dragging = v)"
    />
  </view>
</template>

<script setup>
import { ref, computed } from 'vue'

const images = ref([])
const dragging = ref(false)
const uploaderRef = ref(null)
const token = ref('') // 从登录态获取

const uploadOptions = computed(() => ({
  name: 'file',
  header: token.value ? { Authorization: token.value } : {},
  formData: { module: 'product' }
}))

const  = (e) => console.log('选图', e.count, e.urls)
const onChange = (e) => console.log('列表', e.urls, '封面', e.cover)
const onUploadOk = (e) => console.log('成功', e.url, e.data)
const onUploadFail = (e) => console.log('失败', e.err)
const onSort = (e) => console.log('排序', e.from, e.to)
const onCover = (e) => console.log('封面变更', e.url)
</script>

版本

详见同目录 changelog.md

隐私、权限声明

1. 本插件需要申请的系统权限列表:

相册/相机(选图时由系统授权)

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。