一、功能介绍
需要哦用户点击加号上传图片,并展示所上传图片和能够删除和预览
二、功能实现
采用的uniapp,创建了一个view容器包裹加号图标和展示的图片。
内部展示图片超过9张时候,加号图片隐藏
<view class="img-list">//图片显示列表,循环展示<view v-for="(item,index) in pushData.photoList" :key='index' class="img-list-box">//图片展示和图片点击唤醒uni的预览删除<image :src="item" mode="aspectFit" class="img-item" @tap="imgTypeSelect(item)"></image></view>//加号添加图,样式自定义就好<view v-if="pushData.photoList.length < 9" class="icon-camera" @tap="selectType"></view></view>
点击加号
唤起uni的向上弹出操作菜单
uni.showActionSheet(OBJECT)
点击后又使用看图片选择API
从底部向上弹出操作菜单
OBJECT参数说明
参数 | 类型 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|
title | String | 否 | 菜单标题 | App、H5、支付宝小程序、钉钉小程序、微信小程序 3.4.5+(仅真机有效) |
alertText | String | 否 | 警示文案(同菜单标题) | 微信小程序(仅真机有效) |
itemList | Array<String> | 是 | 按钮的文字数组 | 微信、百度、抖音小程序数组长度最大为6个 |
itemColor | HexColor | 否 | 按钮的文字颜色,字符串格式,默认为"#000000" | App-iOS、飞书小程序不支持 |
popover | Object | 否 | 大屏设备弹出原生选择按钮框的指示区域,默认居中显示 | App-iPad(2.6.6+)、H5(2.9.2) |
success | Function | 否 | 接口调用成功的回调函数,详见返回参数说明 | |
fail | Function | 否 | 接口调用失败的回调函数 | |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
popover 值说明(仅App生效)
值 | 类型 | 说明 |
---|---|---|
top | Number | 指示区域坐标,使用原生 navigationBar 时一般需要加上 navigationBar 的高度 |
left | Number | 指示区域坐标 |
width | Number | 指示区域宽度 |
height | Number | 指示区域高度 |
success返回参数说明
参数 | 类型 | 说明 |
---|---|---|
tapIndex | Number | 用户点击的按钮,从上到下的顺序,从0开始 |
示例
uni.showActionSheet({itemList: ['A', 'B', 'C'],success: function (res) {console.log('选中了第' + (res.tapIndex + 1) + '个按钮');},fail: function (res) {console.log(res.errMsg);}
});
实际代码
selectType() {let that = thislet itemL = ['拍照', '从相册选择照片']uni.showActionSheet({itemList: itemL,success: function(res) {if (res.tapIndex == 0) {uni.chooseImage({sourceType: ['camera'], // 拍照选择success: function(res) {res.tempFilePaths.forEach(path => {uni.uploadFile({url: '11111111', //后端接口地址filePath: path,name: 'file',formData: {},header: {'content-type': 'multipart/form-data',},success: function(uploadFile) {let uploadFiles = JSON.parse(uploadFile.data)that.pushData.photoList.push(uploadFiles.data);}})})}});}if (res.tapIndex == 1) {uni.chooseImage({count: 9 - that.pushData.photoList.length,sourceType: ['album'], //从相册选择success: function(res) {res.tempFilePaths.forEach(path => {uni.uploadFile({url: 'https:1111111', //后端接口地址filePath: path,name: 'file',formData: {},header: {'content-type': 'multipart/form-data',},success: function(uploadFile) {let uploadFiles = JSON.parse(uploadFile.data)that.pushData.photoList.push(uploadFiles.data);}})})}});}
从本地相册选择图片或使用相机拍照。
uni.chooseImage(OBJECT)
App端如需要更丰富的相机拍照API(如直接调用前置摄像头),参考plus.camera
微信小程序从基础库 2.21.0 开始, wx.chooseImage 停止维护,请使用 uni.chooseMedia 代替。
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|
count | Number | 否 | 最多可以选择的图片张数,默认9 | 见下方说明 |
sizeType | Array<String> | 否 | original 原图,compressed 压缩图,默认二者都有 | App、微信小程序、支付宝小程序、百度小程序 |
extension | Array<String> | 否 | 根据文件拓展名过滤,每一项都不能是空字符串。默认不过滤。 | H5(HBuilder X2.9.9+) |
sourceType | Array<String> | 否 | album 从相册选图,camera 使用相机,默认二者都有。如需直接开相机或直接选相册,请只使用一个选项 | |
crop | Object | 否 | 图像裁剪参数,设置后 sizeType 失效 | App 3.1.19+ |
success | Function | 是 | 成功则返回图片的本地文件路径列表 tempFilePaths | |
fail | Function | 否 | 接口调用失败的回调函数 | 小程序、App |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
crop 参数说明
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|
quality | Number | 否 | 取值范围为1-100,数值越小,质量越低(仅对jpg格式有效)。默认值为80。 | |
width | Number | 是 | 裁剪的宽度,单位为px,用于计算裁剪宽高比。 | |
height | Number | 是 | 裁剪的高度,单位为px,用于计算裁剪宽高比。 | |
resize | Boolean | 否 | 是否将width和height作为裁剪保存图片真实的像素值。默认值为true。注:设置为false时在裁剪编辑界面显示图片的像素值,设置为true时不显示 |
success 返回参数说明
参数 | 类型 | 说明 |
---|---|---|
tempFilePaths | Array<String> | 图片的本地文件路径列表 |
tempFiles | Array<Object>、Array<File> | 图片的本地文件列表,每一项是一个 File 对象 |
File 对象结构如下
参数 | 类型 | 说明 |
---|---|---|
path | String | 本地文件路径 |
size | Number | 本地文件大小,单位:B |
name | String | 包含扩展名的文件名称,仅H5支持 |
type | String | 文件类型,仅H5支持 |
选择图片后继续调用上传接口
uni.uploadFile(OBJECT)
将本地资源上传到开发者服务器,客户端发起一个 POST
请求,其中 content-type
为 multipart/form-data
。 如页面通过 uni.chooseImage 等接口获取到一个本地资源的临时文件路径后,可通过此接口将本地资源上传到指定服务器。另外选择和上传非图像、视频文件参考:uni-app 选择和上传非图像、视频文件 - DCloud问答。
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|---|---|---|---|
url | String | 是 | 开发者服务器 url | |
files | Array | 是(files和filePath选其一) | 需要上传的文件列表。使用 files 时,filePath 和 name 不生效。 | App、H5( 2.6.15+) |
fileType | String | 见平台差异说明 | 文件类型,image/video/audio | 仅支付宝小程序,且必填。 |
file | File | 否 | 要上传的文件对象。 | 仅H5(2.6.15+)支持 |
filePath | String | 是(files和filePath选其一) | 要上传文件资源的路径。 | |
name | String | 是 | 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容 | |
header | Object | 否 | HTTP 请求 Header, header 中不能设置 Referer。 | |
timeout | Number | 否 | 超时时间,单位 ms | H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+)、微信小程序、支付宝小程序、抖音小程序、快手小程序 |
formData | Object | 否 | HTTP 请求中其他额外的 form data | |
success | Function | 否 | 接口调用成功的回调函数 | |
fail | Function | 否 | 接口调用失败的回调函数 | |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
注意:
- App支持多文件上传,微信小程序只支持单文件上传,传多个文件需要反复调用本API。所以跨端的写法就是循环调用本API。
files参数说明
files 参数是一个 file 对象的数组,file 对象的结构如下:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
name | String | 否 | multipart 提交时,表单的项目名,默认为 file |
file | File | 否 | 要上传的文件对象,仅H5(2.6.15+)支持 |
uri | String | 是 | 文件的本地地址 |
success 返回参数说明
参数 | 类型 | 说明 |
---|---|---|
data | String | 开发者服务器返回的数据 |
statusCode | Number | 开发者服务器返回的 HTTP 状态码 |
展示 图片和图片的点击预览删除
将图片上传后,获取到每一张上传的图片返回地址,push到展示的图片列表中
<image :src="item" mode="aspectFit" class="img-item"@tap="imgTypeSelect(item)"></image>
点击图片后再次调用向上弹出交互API:uni.showActionSheet
利用点击图片本身的url进行数组寻找,点击预览调用
uni.previewImage(OBJECT)
预览图片。
这里对图片只是一个展示用,所以将存入的图片列表放入就可以预览
其他转发之类的需求可以参考文档中的
longPressActions | Object | 否 | 长按图片显示操作菜单,如不填默认为保存相册 |
点击删除按钮,则根据url寻找index进行列表的截取
// 图片状态选择
imgTypeSelect(item) {let that = thisuni.showActionSheet({itemList: ['预览', '删除'],success: function(res) {if (res.tapIndex == 0) {console.log('删除1', that.pushData.photoList);uni.previewImage({current: item,urls: that.pushData.photoList})}if (res.tapIndex == 1) {let index = that.pushData.photoList.findIndex(url => url === item);if (index !== -1) {that.pushData.photoList.splice(index, 1);}}}});},
不太美观的css
添加图标的css是采用背景图,自行替换或使用别的写法
.icon-camera {display: flex;justify-content: center;align-items: center;width: 210rpx;height: 210rpx;border-radius: 6rpx;margin: 5rpx 0rpx 0rpx 5rpx;background-color: #f4f5f7;// image{// width: 100%;// height: 100%;// }background: url('../iconadd.png');background-size: 100%;}// 媒体列表.img-list {display: flex;flex-wrap: wrap;margin-bottom: 20rpx;}.img-list-box {display: flex;justify-content: center;align-items: center;position: relative;overflow: hidden;}.img-item {width: 210rpx;height: 210rpx;margin: 5rpx;border-radius: 6rpx}