Back to Uni App

Choose Media

docs/api/choose-media.md

2.3.318.8 KB
Original Source
<!-- ## uni.chooseMedia(options) @choosemedia -->

::: sourceCode

uni.chooseMedia(options) @choosemedia

GitCode: https://gitcode.com/dcloud/uni-api/tree/alpha/uni_modules/uni-chooseMedia

GitHub: https://github.com/dcloudio/uni-api/tree/alpha/uni_modules/uni-chooseMedia

:::

拍摄或从手机相册中选择图片或视频。

chooseMedia 兼容性

Web微信小程序AndroidiOSHarmonyOSHarmonyOS(Vapor)
<a style="color:unset;" href="https://vote.dcloud.net.cn/#/?name=uni-app%20x">x</a>4.414.514.514.615.0

参数

名称类型必填默认值兼容性描述
optionsChooseMediaOptions-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -

options 的属性描述

名称类型必备默认值兼容性描述
pageOrientationstring-Web: x; 微信小程序: 4.41; Android: 4.51; iOS: x; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0屏幕方向。默认为page.json中的pageOrientation。
countnumber9Web: x; 微信小程序: -; Android: 4.51; iOS: 4.51; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0最多可以选择的文件个数
mediaTypeArray<string>['image', 'video']Web: x; 微信小程序: -; Android: 4.51; iOS: 4.51; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0album 从相册选视频,camera 使用相机拍摄,合法值:'image'、'video'、'mix'
sourceTypeArray<string>['album', 'camera']Web: x; 微信小程序: -; Android: 4.51; iOS: 4.51; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0album 从相册选视频,camera 使用相机拍摄
maxDurationnumber10Web: x; 微信小程序: 4.41; Android: 4.51; iOS: 4.51; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 30s 之间
camerastring-Web: x; 微信小程序: 4.41; Android: 4.51; iOS: 4.51; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0仅在 sourceType 为 camera 时生效,使用前置或后置摄像头
success(callback: ChooseMediaSuccess) => void-Web: x; 微信小程序: 4.41; Android: -; iOS: -; HarmonyOS: -接口调用成功,返回视频文件的临时文件路径,详见返回参数说明
fail(callback: ChooseMediaFail) => void-Web: x; 微信小程序: 4.41; Android: -; iOS: -; HarmonyOS: -接口调用失败的回调函数
complete(callback: any) => void-Web: x; 微信小程序: 4.41; Android: -; iOS: -; HarmonyOS: -接口调用结束的回调函数(调用成功、失败都会执行)
sizeTypeArray<string>-Web: x; 微信小程序: 4.41; Android: -; iOS: -; HarmonyOS: -是否压缩所选文件,基础库2.25.0前仅对 mediaType 为 image 时有效,2.25.0及以后对全量 mediaType 有效
pageOrientation 的属性描述
合法值兼容性描述
autoWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -自动
portraitWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -竖屏显示
landscapeWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -横屏显示
camera 的属性描述
合法值兼容性描述
frontWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -前置摄像头
backWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -后置摄像头

ChooseMediaSuccess 的属性值 @choosemediasuccess-values

名称类型必备默认值兼容性描述
tempFilesArray<ChooseMediaTempFile>-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -
typestring-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -

tempFiles 的属性描述

名称类型必备默认值兼容性描述
tempFilePathstring-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -选定视频的临时文件路径
fileTypestring-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -文件类型
sizenumber-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -选定视频的数据量大小,单位 kB
byteSizenumber-Web: x; 微信小程序: -; Android: 4.61; iOS: 4.61; HarmonyOS: 4.61; HarmonyOS(Vapor): 5.0视频文件的字节大小,单位 B
durationnumber-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -选定视频的时间长度
heightnumber-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -返回选定视频的长
widthnumber-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -返回选定视频的宽
thumbTempFilePathstring-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -视频缩略图临时文件路径
fileType 的属性描述
合法值兼容性描述
imageWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: --
videoWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: --

type 的属性描述

合法值兼容性描述
imageWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: --
videoWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: --
mixWeb: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: --

ChooseMediaFail 的属性值 @choosemediafail-values

名称类型必备默认值兼容性描述
errCodenumber-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -错误码
errSubjectstring-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -统一错误主题(模块)名称
dataany-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -错误信息中包含的数据
causeError-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -源错误信息,可以包含多个错误,详见SourceError
errMsgstring-Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -

errCode 的属性描述

合法值兼容性描述
1101001Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -用户取消
1101005Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -未获取权限
1101006Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -图片或视频保存失败
1101008Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -拍照或录像失败
1101010Web: x; 微信小程序: -; Android: -; iOS: -; HarmonyOS: -其他错误

Android端返回的路径是content协议。

参见

示例

示例为hello uni-app x alpha分支,与最新HBuilderX Alpha版同步。与最新正式版同步的master分支示例另见

该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验

::: preview

appRedirect https://hellouniappx.dcloud.net.cn/appredirect.html?path=pages/API/choose-media/choose-media

uvue
<template>
  <!-- #ifdef APP -->
  <scroll-view class="page-scroll-view">
  <!-- #endif -->
    <view>
      <page-head :title="title"></page-head>
      <view class="uni-common-mt">
        <view class="uni-list">

          <view class="uni-list-cell cell-pd">
            <view class="uni-list-cell-left uni-label">
              来源
            </view>
            <view class="uni-list-cell-right" @click="chooseMediaSource">
              <text class="click-t">{{sourceTypes[sourceTypeIndex].title}}</text>
            </view>
          </view>

          <view class="uni-list-cell cell-pd">
            <view class="uni-list-cell-left uni-label">
              方式
            </view>
            <view class="uni-list-cell-right" @click="chooseMediaType">
              <text class="click-t">{{(mediaTypes[mediaTypeIndex] as ChooseSource).title}}</text>
            </view>
          </view>

          <view class="uni-list-cell cell-pd">
            <view class="uni-list-cell-left uni-label">
              数量限制
            </view>
            <view class="uni-list-cell-right">
              <input class="click-t" ref="refCountInput" :value="count" type="number" :maxlength="1" @blur="chooseMediaCount"/>
            </view>
          </view>

          <!-- #ifdef APP-ANDROID -->
          <view class="uni-list-cell cell-pd">
            <view class="uni-list-cell-left uni-label">
              屏幕方向
            </view>
            <view class="uni-list-cell-right" @click="chooseOrientationType">
              <text class="click-t">{{orientationTypes[orientationTypeIndex].title}}</text>
            </view>
          </view>
          <!-- #endif -->

          <view class="uni-list-cell cell-pd">
            <view class="uni-list-cell-left uni-label">
              摄像头
            </view>
            <view class="uni-list-cell-right" @click="chooseCameraType">
              <text class="click-t">{{cameraTypes[cameraTypeIndex].title}}</text>
            </view>
          </view>
        </view>
        <!-- #ifdef APP-IOS -->
        <input-data title="最长拍摄时间,单位秒" defaultValue="10" type="number" @confirm="onMaxDurationConfirm"></input-data>
        <!-- #endif -->
        <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">{{mediaList.length}}/{{count}}</text>
            </view>
          </view>
          <view class="uni-flex" style="flex-wrap: wrap;">
            <view v-for="(file,index) in mediaList" :key="index" class="uni-uploader__input-box" style="border: 0;">
              <image style="width: 104px; height: 104px;" :src="file.imagePath" @tap="previewMedia(index)">
              </image>
              <image src="/static/plus.png" class="image-remove" @click="removeMedia(index)"></image>
            </view>
            <image class="uni-uploader__input-box" @tap="chooseMedia" src="/static/plus.png"></image>
          </view>
        </view>
      </view>
    </view>
  <!-- #ifdef APP -->
  </scroll-view>
  <!-- #endif -->
</template>

<script setup lang="uts">
  type FileSource = {
    imagePath : string;
    filePath : string;
    fileType : string;
  };
  type ChooseSource = {
    value : string[];
    title : string;
  };
  const sourceTypeList : ChooseSource[] = [
    {
      value: ['camera'],
      title: '拍摄',
    },
    {
      value: ['album'],
      title: '相册',
    },
    {
      value: ['camera', 'album'],
      title: '拍摄或相册',
    }
  ];

  const mediaTypeList : ChooseSource[] = [
    {
      value: ['image'],
      title: '仅图片',
    },
    {
      value: ['video'],
      title: '仅视频',
    },
    {
      value: ['image', 'video'],
      title: '不限制',
    }
  ];

  const orientationTypeList : ChooseSource[] = [
    {
      value: ['portrait'],
      title: '竖屏',
    },
    {
      value: ['landscape'],
      title: '横屏',
    },
    {
      value: ['auto'],
      title: '自动',
    }
  ];
  const cameraTypeList : ChooseSource[] = [
    {
      value: ['front'],
      title: '前置摄像头',
    },
    {
      value: ['back'],
      title: '后置摄像头',
    }
  ];

  const title = ref('chooseMedia')
  const mediaList = ref([] as Array<FileSource>)
  const sourceTypeIndex = ref(2)
  const mediaTypeIndex = ref(2)
  const cameraTypeIndex = ref(1)
  const orientationTypeIndex = ref(0)
  const albumModeTypeIndex = ref(0)
  const count = ref(9)
  const maxDuration = ref(10)
  const sourceTypes = ref(sourceTypeList as ChooseSource[])
  const mediaTypes = ref(mediaTypeList as ChooseSource[])
  const cameraTypes = ref(cameraTypeList as ChooseSource[])
  const orientationTypes = ref(orientationTypeList as ChooseSource[])
  const refCountInput = ref<UniElement | null>(null)

  const chooseMediaSource = () => {
    uni.showActionSheet({
      itemList: ['拍摄', '相册', '拍摄或相册'],
      success: (e) => {
        sourceTypeIndex.value = e.tapIndex
      }
    })
  }

  const chooseMediaType = () => {
    uni.showActionSheet({
      itemList: ['仅图片', '仅视频', '不限制'],
      success: (e) => {
        mediaTypeIndex.value = e.tapIndex
      }
    })
  }

  const chooseMediaCount = (event: UniInputBlurEvent) => {
    let countValue = parseInt(event.detail.value)
    if (countValue < 1 || countValue > 9 || isNaN(countValue)) {
      uni.showToast({
        position: "bottom",
        title: "图片数量应该不小于1不大于9"
      })
      return
    }
    count.value = countValue
  }

  const chooseOrientationType = () => {
    uni.showActionSheet({
      itemList: ['竖屏', '横屏', '自动'],
      success: (e) => {
        orientationTypeIndex.value = e.tapIndex
      }
    })
  }

  const chooseCameraType = () => {
    uni.showActionSheet({
      itemList: ['前置', '后置'],
      success: (e) => {
        cameraTypeIndex.value = e.tapIndex
      }
    })
  }

  const onMaxDurationConfirm = (value: number) => {
    maxDuration.value = value;
  }

  const chooseMedia = () => {
    if (mediaList.value.length >= count.value) {
      const message = "已经有" + count.value + "个了,请删除部分后重新选择";
      uni.showToast({
        position: "bottom",
        title: message
      })
      return
    }

    uni.chooseMedia({
      count: count.value - mediaList.value.length,
      sourceType: sourceTypeList[sourceTypeIndex.value].value,
      mediaType: mediaTypeList[mediaTypeIndex.value].value,
      camera: cameraTypeList[cameraTypeIndex.value].value[0],
      // #ifdef APP-IOS
      maxDuration: maxDuration.value,
      // #endif
      // #ifdef APP-ANDROID
      pageOrientation: orientationTypeList[orientationTypeIndex.value].value[0],
      // #endif
      success: (res) => {
        const tempFiles : ChooseMediaTempFile[] = res.tempFiles as ChooseMediaTempFile[];
        for (let i = 0; i < tempFiles.length; i++) {
          const tempFile : ChooseMediaTempFile = tempFiles[i]
          const imagePath = tempFile.fileType == "image" ? tempFile.tempFilePath : tempFile.thumbTempFilePath;
          const file : FileSource = { imagePath: imagePath!, filePath: tempFile.tempFilePath, fileType: tempFile.fileType };
          mediaList.value.push(file);
        }
      },
      fail: (err) => {
        console.log("err: ", JSON.stringify(err));
        uni.showToast({
          title:"choose media error.code:" + err.errCode+";message:"+err.errMsg,
          position:"bottom"
        })
      }
    })
  }

  const previewMedia = (index: number) => {
    const file : FileSource = mediaList.value[index];
    if (file.fileType == "image") {
      uni.previewImage({
        current: 0,
        urls: [file.filePath]
      })
    } else {
      uni.$once("__ONFULLVIDEOLOAD", () => {
        uni.$emit("__ONRECEIVEURL", {
          "url": file.filePath,
          "cover": file.imagePath
        })
      })
      const url = "/pages/API/choose-media/fullscreen-video";
      uni.navigateTo({
        url: url,
      })
    }
  }

  const removeMedia = (index: number) => {
    mediaList.value.splice(index, 1)
  }
</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;
  }
</style>

:::

通用类型

GeneralCallbackResult

名称类型必备默认值兼容性描述
errMsgstring-Web: -; 微信小程序: 4.41; Android: -; iOS: -; HarmonyOS: -错误信息

Tips

  • chooseMedia的相册选择在App平台是系统UI,其风格不同rom可能有差异。多选时有的是长按、有的是checkbox。系统UI的暗黑模式、国际化跟随系统,而不跟随App。
  • android端由于系统或ROM的限制,拍照的maxDurationcamera属性在部分手机上不生效。
  • 从HBuilderX4.61版起,ChooseMediaSuccess中的duration、size精度统一调整为小数点后3位数
  • iOS端拍照和相册选择会在应用沙盒目录的cache目录产生临时文件,位置详见。如需主动删除临时文件,使用uni.getFileSystemManager
  • App平台通过chooseMedia选择媒体文件后,默认没有压缩,需自行调用 uni.compressImageuni.compressVideo 来压缩。