docs/api/choose-image.md
::: sourceCode
GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-media
GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-media
:::
从本地相册选择图片或使用相机拍照
| Web | 微信小程序 | Android | iOS | HarmonyOS | HarmonyOS(Vapor) |
|---|---|---|---|---|---|
| 4.0 | 4.41 | 3.9 | 4.11 | 4.61 | 5.0 |
| 名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| options | ChooseImageOptions | 是 | - | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| pageOrientation | string | 否 | - | Web: x; 微信小程序: x; Android: 4.33; iOS: 4.33; HarmonyOS: x | 屏幕方向。默认为page.json中的pageOrientation。 |
| albumMode | string | 否 | "custom" | Web: x; 微信小程序: x; Android: 4.33; iOS: x; HarmonyOS: x | 图片选择模式 |
| count | number | 否 | 9 | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 最多可以选择的图片张数,app端不限制,微信小程序最多可支持20个。 |
| sizeType | Array<string> | 否 | ['original','compressed'] | Web: x; 微信小程序: 4.41; Android: 3.9; iOS: 4.11; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0 | original 原图,compressed 压缩图,默认二者都有 |
| sourceType | Array<string> | 否 | ['album','camera'] | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | album 从相册选图,camera 使用相机,默认二者都有 |
| extension | Array<string> | 否 | - | Web: 4.0; 微信小程序: 4.41; Android: x; iOS: x; HarmonyOS: x | 根据文件拓展名过滤,每一项都不能是空字符串。默认不过滤。仅H5支持 |
| crop | ChooseImageCropOptions | 否 | - | Web: x; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: x | 图像裁剪参数,设置后 sizeType 失效。 |
| success | (callback: ChooseImageSuccess) => void | 否 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 成功则返回图片的本地文件路径列表 tempFilePaths |
| fail | (callback: ChooseImageFail) => void | 否 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 接口调用失败的回调函数 |
| complete | (callback: any) => void | 否 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 接口调用结束的回调函数(调用成功、失败都会执行) |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| auto | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 自动 |
| portrait | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 竖屏显示 |
| landscape | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 横屏显示 |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| custom | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 自定义媒体选择器 |
| system | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 系统媒体选择器 |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| width | number | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 裁剪的宽度,单位为px,用于计算裁剪宽高比。 |
| height | number | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 裁剪的高度,单位为px,用于计算裁剪宽高比。 |
| quality | number | 否 | 80 | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 取值范围为1-100,数值越小,质量越低(仅对jpg格式有效)。默认值为80。 |
| resize | boolean | 否 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 是否将width和height作为裁剪保存图片真实的像素值。默认值为true。注:设置为false时在裁剪编辑界面显示图片的像素值,设置为true时不显示。 |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| errSubject | string | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 调用API的名称 |
| errMsg | string | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 描述信息 |
| tempFilePaths | Array<string> | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 图片的本地文件路径列表 |
| tempFiles | Array<ChooseImageTempFile> | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 图片的本地文件列表 |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| path | string | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 本地文件路径 |
| size | number | 是 | - | Web: -; 微信小程序: -; Android: 3.9; iOS: 4.11; HarmonyOS: - | 本地文件大小,单位:B |
| name | string | 否 | - | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 包含扩展名的文件名称,仅H5支持 |
| type | string | 否 | - | Web: -; 微信小程序: -; Android: x; iOS: x; HarmonyOS: - | 文件类型,仅H5支持 |
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| errCode | number | 是 | - | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 错误码 |
| errSubject | string | 是 | - | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 统一错误主题(模块)名称 |
| data | any | 否 | - | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 错误信息中包含的数据 |
| cause | Error | 否 | - | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 源错误信息,可以包含多个错误,详见SourceError |
| errMsg | string | 是 | - | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - |
| 合法值 | 兼容性 | 描述 |
|---|---|---|
| 1101001 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 用户取消 |
| 1101002 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | urls至少包含一张图片地址 |
| 1101003 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 文件不存在 |
| 1101004 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 图片加载失败 |
| 1101005 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 未获取权限 |
| 1101006 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 图片或视频保存失败 |
| 1101007 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 图片裁剪失败 |
| 1101008 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 拍照或录像失败 |
| 1101009 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 图片压缩失败 |
| 1101010 | Web: -; 微信小程序: -; Android: -; iOS: -; HarmonyOS: - | 其他错误 |
示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见 ::: preview https://hellouniappx.dcloud.net.cn/web/#/pages/API/choose-image/choose-image
appRedirect https://hellouniappx.dcloud.net.cn/appredirect.html?path=pages/API/choose-image/choose-image
示例
<template>
<!-- #ifdef APP -->
<scroll-view class="page-scroll-view">
<!-- #endif -->
<page-head :title="title"></page-head>
<view class="uni-common-mt">
<view class="uni-list">
<view class="uni-list-cell cell-pd">
<text class="uni-list-cell-left uni-label">
图片来源
</text>
<view class="uni-list-cell-right" @click="chooseImageSource">
<text class="click-t">{{sourceType[sourceTypeIndex]}}</text>
</view>
</view>
<view class="uni-list-cell cell-pd">
<text class="uni-list-cell-left uni-label">
图片质量
</text>
<view class="uni-list-cell-right" @click="chooseImageType">
<text class="click-t">{{sizeType[sizeTypeIndex]}}</text>
</view>
</view>
<view class="uni-list-cell cell-pd">
<text class="uni-list-cell-left uni-label">
数量限制
</text>
<view class="uni-list-cell-right">
<input class="click-t" :value="count" type="number" :maxlength="1" @blur="chooseImageCount" />
</view>
</view>
<!-- #ifdef APP-ANDROID || APP-IOS -->
<view class="uni-list-cell cell-pd">
<text class="uni-list-cell-left uni-label">
屏幕方向
</text>
<view class="uni-list-cell-right" @click="chooseOrientationType">
<text class="click-t">{{orientationType[orientationTypeIndex]}}</text>
</view>
</view>
<!-- #endif -->
<!-- #ifdef APP-ANDROID -->
<view class="uni-list-cell cell-pd">
<text class="uni-list-cell-left uni-label">
相册模式
</text>
<view class="uni-list-cell-right" @click="albumModeChange">
<text class="click-t">{{albumModeType[albumModeTypeIndex]}}</text>
</view>
</view>
<!-- #endif -->
<view class="uni-list-cell cell-pd">
<text class="uni-list-cell-left uni-label">
图像裁剪
</text>
<view class="uni-list-cell-right">
<switch :checked="isCrop" @change="switchCrop"></switch>
</view>
</view>
<view ref="cropOptionNode" class="crop-option"
:style="{'height':isCrop?'200px':'0px','margin-bottom':isCrop?'11px':'0px'}">
<view class="uni-list-cell cell-pd">
<view class="uni-list-cell-left item_width">
图片质量(%)
</view>
<view class="uni-list-cell-right">
<input :value="cropPercent" @confirm="cropPercentConfim" type="number" maxlength="-1" />
</view>
</view>
<view class="uni-list-cell cell-pd">
<view class="uni-list-cell-left item_width">
裁剪宽度(px)
</view>
<view class="uni-list-cell-right">
<input :value="cropWidth" @confirm="cropWidthConfim" type="number" maxlength="-1" />
</view>
</view>
<view class="uni-list-cell cell-pd">
<view class="uni-list-cell-left item_width">
裁剪高度(px)
</view>
<view class="uni-list-cell-right">
<input :value="cropHeight" @confirm="cropHeightConfim" type="number" maxlength="-1" />
</view>
</view>
<view class="uni-list-cell cell-pd">
<view class="uni-list-cell-left item_width">
保留原宽高
</view>
<view class="uni-list-cell-right">
<switch :checked="cropResize" @change="cropResizeChange"></switch>
</view>
</view>
</view>
</view>
<view class="uni-list list-pd" style="padding: 15px;">
<view class="uni-flex" style="margin-bottom: 10px;">
<view class="uni-list-cell-left">点击可预览选好的图片</view>
<view style="margin-left: auto;">
<text class="click-t">{{imageList.length}}/{{count}}</text>
</view>
</view>
<view class="uni-flex" style="flex-wrap: wrap;">
<view v-for="(image,index) in imageList" :key="index" class="uni-uploader__input-box" style="border: 0;">
<image style="width: 104px; height: 104px;" :src="image" @tap="previewImage(index)">
</image>
<image src="/static/plus.png" class="image-remove" @click="removeImage(index)"></image>
</view>
<image class="uni-uploader__input-box" @tap="chooseImage" src="/static/plus.png"></image>
</view>
</view>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
const sourceTypeArray = [
['camera'],
['album'],
['camera', 'album']
]
const sizeTypeArray = [
['compressed'],
['original'],
['compressed', 'original']
]
const orientationTypeArray = [
'portrait',
'landscape',
'auto'
]
const albumModeTypeArray = [
"custom",
"system"
]
// 响应式数据
const title = ref('chooseImage')
const imageList = ref([] as Array<string>)
const sourceTypeIndex = ref(2)
const sourceType = ref(['拍照', '相册', '拍照或相册'])
const sizeTypeIndex = ref(2)
const sizeType = ref(['压缩', '原图', '压缩或原图'])
const orientationTypeIndex = ref(0)
const orientationType = ref(['竖屏', '横屏', '自动'])
const albumModeTypeIndex = ref(0)
const albumModeType = ref(["自定义相册","系统相册"])
const count = ref(9)
const isCrop = ref(false)
const cropPercent = ref(80)
const cropWidth = ref(100)
const cropHeight = ref(100)
const cropResize = ref(false)
// 生命周期钩子
onPageHide(() => {
console.log("Page Hide");
})
onUnload(() => {
imageList.value = [];
sourceTypeIndex.value = 2
sourceType.value = ['拍照', '相册', '拍照或相册']
sizeTypeIndex.value = 2
sizeType.value = ['压缩', '原图', '压缩或原图']
orientationTypeIndex.value = 0
orientationType.value = ['竖屏', '横屏', '自动']
})
// 方法
const cropHeightConfim = (e: InputConfirmEvent) => {
let value = parseInt(e.detail.value)
if (value > 0) {
cropHeight.value = value
} else {
uni.showToast({
position: "bottom",
title: "裁剪高度需要大于0"
})
}
}
const cropWidthConfim = (e: InputConfirmEvent) => {
let value = parseInt(e.detail.value)
if (value > 0) {
cropWidth.value = value
} else {
uni.showToast({
position: "bottom",
title: "裁剪宽度需要大于0"
})
}
}
const cropPercentConfim = (e: InputConfirmEvent) => {
let value = parseInt(e.detail.value)
if (value > 0 && value <= 100) {
cropPercent.value = value
} else {
uni.showToast({
position: "bottom",
title: "请输入0~100之间的值"
})
}
}
const albumModeChange = () => {
uni.showActionSheet({
itemList: albumModeType.value,
success: (e) => {
albumModeTypeIndex.value = e.tapIndex
}
})
}
const cropResizeChange = (e: UniSwitchChangeEvent) => {
cropResize.value = e.detail.value
}
const switchCrop = (e: UniSwitchChangeEvent) => {
isCrop.value = e.detail.value
}
const removeImage = (index: number) => {
imageList.value.splice(index, 1)
}
const chooseImageSource = () => {
uni.showActionSheet({
itemList: ['拍照', '相册', '拍照或相册'],
success: (e) => {
sourceTypeIndex.value = e.tapIndex
}
})
}
const chooseImageType = () => {
uni.showActionSheet({
itemList: ['压缩', '原图', '压缩或原图'],
success: (e) => {
sizeTypeIndex.value = e.tapIndex
}
})
}
const chooseOrientationType = () => {
uni.showActionSheet({
itemList: ['竖屏', '横屏', '自动'],
success: (e) => {
orientationTypeIndex.value = e.tapIndex
}
})
}
const chooseImageCount = (event: InputBlurEvent) => {
let countValue = parseInt(event.detail.value)
if (countValue < 0) {
uni.showToast({
position: "bottom",
title: "图片数量应该大于0"
})
return
}
count.value = countValue
}
const chooseImage = () => {
if (imageList.value.length >= count.value) {
uni.showToast({
position: "bottom",
title: `已经有 ${count.value} 张图片了,请删除部分图片之后重新选择`
})
return
}
uni.chooseImage({
sourceType: sourceTypeArray[sourceTypeIndex.value],
sizeType: sizeTypeArray[sizeTypeIndex.value],
crop: isCrop.value ? { "quality": cropPercent.value, "width": cropWidth.value, "height": cropHeight.value, "resize": cropResize.value } as ChooseImageCropOptions : null,
count: count.value - imageList.value.length,
// #ifdef APP
pageOrientation: orientationTypeArray[orientationTypeIndex.value],
// #endif
// #ifdef APP-ANDROID
albumMode: albumModeTypeArray[albumModeTypeIndex.value],
// #endif
success: (res) => {
imageList.value = imageList.value.concat(res.tempFilePaths);
console.log("imageList: ", imageList.value)
},
fail: (err) => {
console.log("err: ", JSON.stringify(err));
uni.showToast({
title:"choose image error.code:" + err.errCode+";message:"+err.errMsg,
position:"bottom"
})
}
})
}
const previewImage = (index: number) => {
uni.previewImage({
current: index,
urls: imageList.value
})
}
</script>
<style>
.cell-pd {
padding: 11px 15px;
}
.click-t {
color: darkgray;
}
.list-pd {
margin-top: 25px;
}
.uni-uploader__input-box {
margin: 5px;
width: 104px;
height: 104px;
border: 1px solid #D9D9D9;
}
.uni-uploader__input {
position: absolute;
z-index: 1;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.image-remove {
transform: rotate(45deg);
width: 25px;
height: 25px;
position: absolute;
top: 0;
right: 0;
border-radius: 13px;
background-color: rgba(200, 200, 200, 0.8);
}
.item_width {
width: 130px;
}
.crop-option {
margin-left: 11px;
margin-right: 11px;
border-radius: 11px;
background-color: #eee;
transition-property: height, margin-bottom;
transition-duration: 200ms;
}
</style>
:::
| 名称 | 类型 | 必备 | 默认值 | 兼容性 | 描述 |
|---|---|---|---|---|---|
| errMsg | string | 是 | - | Web: -; 微信小程序: 4.41; Android: -; iOS: -; HarmonyOS: - | 错误信息 |
App平台的相册选择,有custom自定义方式和system系统方式。这2种方式有不少区别:
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />和<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />权限移除。配置方式参考移除Android权限。sourceType为['album']、albumMode为system、sizeType为['original']并且未设置crop时,支持返回Uri地址。albumMode的system属性打开的是系统的图片选择器;custom属性打开的是uni-app x框架提供的图片选择器。sizeType仅支持设置['original']或['compressed']。在Android 11及以上的系统中,设置system调用的是系统的照片选择器,低于android 11的系统中会调用系统的文件选择器。