更新记录
1.0.0(2026-11-12)
- 首次发布:iOS / Android 仿微信选图页(相册切换、多选序号、大图预览、原图、视频试看、原生图片编辑)
- 参数:count、mediaType、maxImageCount、maxVideoCount、mixSelect、maxDuration、minDuration、maxVideoSize、showOriginal、defaultOriginal、editable、videoPlayable、columns、themeColor、confirmText、cancelText、compressQuality、compressMaxSide、haptic
- 鸿蒙调用系统选择器 PhotoViewPicker
平台兼容性
uni-app x(5.31)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 5.0 | 15 | 12 | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | √ | √ |
tlink-photo-picker 仿微信图片 / 视频选择器
uni-app x 原生选图插件。原生层读取系统相册,界面是插件自带的 uvue 页面,交互对齐微信。
目录
功能
iOS / Android:
- 相册列表:顶部胶囊切换相册,第一项为「最近项目」,空相册不显示
- 多选:带序号;跨相册保留已选;可限制总数、图片数、视频数,可禁止图片视频混选
- 视频:显示时长角标,可限制最短、最长时长和最大文件大小,支持预览中试看
- 大图预览:左右翻页(可在整个相册里连续翻),双击放大,双指缩放,单击显隐上下栏;底部已选缩略图条,点击跳转
- 原图开关:可隐藏,可设默认勾选
- 图片编辑(原生页面):涂鸦、表情、文字、裁剪旋转、马赛克;编辑后自动勾选,缩略图换成编辑结果
- 可选压缩:未勾原图时按质量和长边压缩,GIF 跳过
- 主题色、按钮文字、网格列数可配置;宽屏(≥ 600px)自动 6 列
- iOS「部分照片」授权:顶部提示条和「管理」入口;Android 13 分媒体权限、14「部分照片」
- 缩略图按滚动位置流式生成,万张图库不卡;HEIC 自动转 JPEG,GIF / PNG / JPEG 原样导出
平台支持
| 平台 | 支持 | 实现 |
|---|---|---|
| uni-app x iOS | iOS 15+ | 自建选图页(Photos / PhotosUI) |
| uni-app x Android | Android 5.0+(minSdk 21) | 自建选图页(MediaStore) |
| uni-app x 鸿蒙 | √(功能精简) | 系统选择器 PhotoViewPicker,免权限 |
| uni-app x Web / 小程序 | × | 调用直接走 fail(errCode 2) |
| uni-app(Vue 版) | × | 不支持 |
安装
- 在插件市场导入插件。HBuilderX 会提示把选图页合并进
pages.json,选「合并」。 - 没有合并时,手动在
pages.json的pages数组里加(不能放首位):
{
"path": "uni_modules/tlink-photo-picker/pages/picker/picker",
"style": {
"navigationBarTitleText": "选择图片",
"navigationStyle": "custom",
"navigationBarTextStyle": "white",
"disableSwipeBack": true
}
}
- 视频试看用到
video组件:在manifest.json的「App 模块配置」里勾选 Video(或在源码视图app-android/app-ios的distribute.modules中加"uni-video": {})。 - 插件含原生代码,必须重新制作自定义基座后运行,标准基座不可用。付费插件试用也只能在自定义基座上进行。
快速开始
import {
chooseMedia,
TLChooseMediaResult,
TLChooseMediaFail
} from '@/uni_modules/tlink-photo-picker/common/index.uts'
chooseMedia({
count: 9,
success: (res : TLChooseMediaResult) => {
for (let i = 0; i < res.tempFiles.length; i++) {
const f = res.tempFiles[i]
console.log(f.type, f.path, f.width, f.height, f.size)
}
},
fail: (err : TLChooseMediaFail) => {
if (err.errCode != 1) {
uni.showToast({ title: err.errMsg, icon: 'none' })
}
}
})
chooseMedia 参数
chooseMedia(options : TLChooseMediaOptions) : void,所有参数都可省略。
选择范围
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| count | number | 9 | 最多选几项(图片 + 视频合计),最小 1 |
| mediaType | string | 'mix' |
'mix' 图片和视频;'image' 只显示图片;'video' 只显示视频 |
| maxImageCount | number | 0 | 图片最多几张,0 表示只受 count 限制 |
| maxVideoCount | number | 0 | 视频最多几个,0 表示只受 count 限制 |
| mixSelect | boolean | true | 是否允许图片和视频混选。false 时选了图片后视频置灰,反之亦然(类似朋友圈) |
视频限制
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| maxDuration | number | 0 | 视频最长秒数,超出时点击提示「只能选择 X 以内的视频」;0 不限 |
| minDuration | number | 0 | 视频最短秒数,不足时提示「只能选择 X 以上的视频」;0 不限 |
| maxVideoSize | number | 0 | 视频最大字节数。超出的视频仍会返回,但 path 为空串、size 为实际大小,方便你提示「文件过大」;0 不限 |
| videoPlayable | boolean | true | 预览中视频是否显示播放按钮试看 |
原图与压缩
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| showOriginal | boolean | true | 是否显示「原图」开关。隐藏时 original 恒为 false |
| defaultOriginal | boolean | false | 「原图」默认是否勾选(showOriginal 为 false 时无效) |
| compressQuality | number | 0 | 未勾原图时的图片压缩质量 1-100;0 不压缩,原样返回原尺寸文件。GIF 不压缩 |
| compressMaxSide | number | 1600 | 压缩时长边上限(px),超过的等比缩小;0 只降质量不缩放。compressQuality 为 0 时无效 |
不开压缩时插件不处理图片:勾不勾原图都返回原尺寸文件,你可以根据 original 自行压缩。
编辑
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| editable | boolean | true | 预览中图片是否显示「编辑」入口(涂鸦 / 表情 / 文字 / 裁剪旋转 / 马赛克) |
界面
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| themeColor | string | '#07C160' |
主题色,作用于勾选序号、完成按钮、原图开关、当前相册勾、预览缩略图条描边、「管理」文字 |
| confirmText | string | '完成' |
完成按钮文字,选中后自动显示为「完成(3)」 |
| cancelText | string | '取消' |
左上角取消文字 |
| columns | number | 0 | 网格列数 1-8;0 自动:窗口宽度 < 600px 为 4 列,否则 6 列 |
| haptic | boolean | false | 点击时轻震(uni.vibrateShort);基座不含震动模块时静默跳过 |
回调
| 参数 | 类型 | 说明 |
|---|---|---|
| success | (res : TLChooseMediaResult) => void |
选择完成。开了压缩时在压缩结束后回调 |
| fail | (err : TLChooseMediaFail) => void |
取消或失败,见错误码 |
| complete | () => void |
成功或失败后都会调用 |
success 返回值
TLChooseMediaResult
| 字段 | 类型 | 说明 |
|---|---|---|
| original | boolean | 用户是否勾选了「原图」 |
| tempFiles | TLMediaFile[] | 选中的文件,顺序与勾选序号一致 |
TLMediaFile
| 字段 | 类型 | 说明 |
|---|---|---|
| type | string | 'image' 或 'video' |
| path | string | 本地绝对路径,可直接给 image、video、uni.uploadFile;视频超过 maxVideoSize 时为空串 |
| width | number | 宽(px)。编辑过的是编辑后尺寸,压缩过的是压缩后尺寸 |
| height | number | 高(px) |
| duration | number | 视频时长(秒),图片为 0 |
| size | number | 文件字节数 |
| compressed | boolean | 是否经过插件压缩 |
文件格式:GIF / JPEG / PNG 原样导出,HEIC / HEIF 等其他图片格式转为原尺寸 JPEG;编辑过的图片为 JPEG;视频为原文件拷贝。
fail 错误码
TLChooseMediaFail:{ errCode : number, errMsg : string },errMsg 以 chooseMedia:fail 开头。
| errCode | 含义 | 建议处理 |
|---|---|---|
| 1 | 用户取消(点取消、返回,或鸿蒙选择器里没选) | 忽略 |
| 2 | 当前平台不支持(Web、小程序) | 改用 uni.chooseImage |
| 3 | 打开选图页失败 | 检查 pages.json 是否注册了选图页 |
| 4 | 没有相册权限,用户没去开启就离开了 | 可引导到系统设置 |
| 5 | 已有选图页打开(重复调用) | 忽略,防连点 |
常用场景示例
聊天发图(同微信)
chooseMedia({
count: 9,
maxDuration: 300,
maxVideoSize: 1024 * 1024 * 1024,
confirmText: '发送',
compressQuality: 80,
compressMaxSide: 1600,
success: (res) => {
for (let i = 0; i < res.tempFiles.length; i++) {
const f = res.tempFiles[i]
if (f.type == 'video' && f.path.length == 0) {
uni.showToast({ title: '视频超过 1GB,无法发送', icon: 'none' })
continue
}
// 上传 f.path
}
}
})
朋友圈:图片最多 9 张、视频只能 1 个、不能混选
chooseMedia({
count: 9,
maxVideoCount: 1,
mixSelect: false,
maxDuration: 30,
minDuration: 3
})
换头像:单张图片,不要原图和视频
chooseMedia({
count: 1,
mediaType: 'image',
showOriginal: false,
compressQuality: 85,
compressMaxSide: 800,
success: (res) => {
const path = res.tempFiles[0].path
}
})
只选视频、不允许编辑和试看、自定义主题
chooseMedia({
mediaType: 'video',
count: 3,
videoPlayable: false,
editable: false,
themeColor: '#2B7CFF',
confirmText: '下一步',
cancelText: '关闭'
})
各平台差异
| 能力 | iOS | Android | 鸿蒙 |
|---|---|---|---|
| 自建选图界面 | √ | √ | ×(系统选择器) |
| count / mediaType | √ | √ | √ |
| maxImageCount / maxVideoCount / mixSelect | √ | √ | × |
| maxDuration / minDuration | √ | √ | × |
| maxVideoSize | √ | √ | √ |
| 原图开关(showOriginal / defaultOriginal) | √ | √ | ×(original 恒为 false) |
| compressQuality / compressMaxSide | √ | √ | √ |
| 编辑、试看、主题色、文字、列数、轻震 | √ | √ | × |
| 返回 width / height | √ | √ | 图片 √,视频为 0 |
| 返回 duration | √ | √ | 0,需要时用 uni.getVideoInfo |
权限与隐私
iOS
- 插件的
utssdk/app-ios/info.plist已带NSPhotoLibraryUsageDescription,默认文案为「需要访问你的相册,以便选择照片和视频」,需要修改时直接改该文件。 - 同一文件设置了
PHPhotoLibraryPreventAutomaticLimitedAccessAlert = true,关闭系统在「部分照片」授权下的自动提示(对整个 App 生效),由选图页顶部的「管理」入口替代。 - 首次打开选图页才申请权限。
Android
- 插件声明的权限:
READ_EXTERNAL_STORAGE(Android 12 及以下)、READ_MEDIA_IMAGES、READ_MEDIA_VIDEO(13+)、READ_MEDIA_VISUAL_USER_SELECTED(14+ 部分照片)。 - 首次打开选图页才申请。国内应用市场上架时,需在隐私政策中说明相册用途,并按市场要求在申请前展示用途说明。
- 用户拒绝后,选图页显示「去设置」按钮,并弹框引导到系统设置。
鸿蒙
- 使用系统 PhotoViewPicker,不需要声明任何权限。
数据
- 插件不联网、不采集任何数据。
- 选中的文件拷贝到本应用缓存目录:iOS / Android 由插件定期清理旧的导出文件和缩略图缓存,鸿蒙每次选择前清理一天前的文件。需要长期保存时请自行拷贝到
uni.env.USER_DATA_PATH。
底层原生 API
自己画界面时可以直接用原生层。引入:import { ... } from '@/uni_modules/tlink-photo-picker'。跨桥的列表都是 JSON 字符串,自行 JSON.parse。所有回调都在主线程触发。鸿蒙上只有 photoPickSystem 可用,其余为空实现。
| 函数 | 说明 |
|---|---|
photoAuthStatus() : string |
相册权限:authorized / limited(部分照片)/ notDetermined / denied。Android 无法区分没问过和拒绝过,统一返回 notDetermined |
photoRequestAuth(callback : (status : string) => void) |
申请相册权限,回调授权结果(取值同上) |
photoManageLimited(callback : () => void) |
「部分照片」授权下让用户重新选择可访问的照片,关闭后回调,应重新加载。Android 上系统不再弹框时会跳到应用设置页 |
photoLoadAlbums(callback : (json : string) => void) |
相册列表 [{ id, title, count, cover }]。第一项是「最近项目」(id 为空串),cover 为封面资源 id,空相册不返回 |
photoLoadAssets(albumId : string, callback : (json : string) => void) |
相册内全部图片和视频 [{ id, type, duration }],按拍摄时间倒序;albumId 传空串取「最近项目」 |
photoSetThumbnailCallback(callback : (key : string, path : string) => void) |
挂常驻缩略图回调,每生成一张回调一次。key 为 `${size}#${id}`,path 为本地图片路径 |
photoClearThumbnailCallback() |
摘掉缩略图回调,同时作废本次的编辑结果。页面关闭时调用 |
photoRequestThumbnails(ids : string[], size : number) |
按需生成缩略图,size 为长边像素;已有缓存的立即回调。建议只请求可见区域 |
photoExportAssets(ids : string[], maxVideoBytes : number, callback : (json : string) => void) |
按顺序导出 [{ type, path, width, height, duration, size }],读取失败的项跳过;视频超过 maxVideoBytes 时 path 为空,传 0 不限 |
photoEditImage(id : string, callback : (json : string) => void) |
打开原生编辑页,回调 { status: 'done', path, width, height } / { status: 'cancel' } / { status: 'fail' }。编辑后该资源的缩略图和导出都用编辑结果 |
photoPickSystem(count : number, mediaType : string, maxVideoBytes : number, callback : (json : string) => void) |
仅鸿蒙:系统选择器,回调 [{ type, path, size, width, height }],取消为 []。mediaType 取 mix / image / video |
常见问题
调用后没反应 / errCode 3:选图页没注册到 pages.json,按安装第 2 步添加。
报「模块不存在」或原生方法找不到:没有重新打自定义基座,或 iOS 覆盖安装没更新原生库。卸载旧 App 后重新打基座安装。
视频点播放没反应:manifest 没勾选 Video 模块,勾选后重新打基座。
直接 uni.navigateTo 打开选图页拿不到结果:必须通过 chooseMedia 打开,结果走回调。
iOS 只显示部分照片:用户授权的是「部分照片」,点顶部「管理」增减;或引导用户到设置改为「完全访问」。
选图页颜色:固定深色风格(同微信),不跟随系统暗黑模式;主题色可用 themeColor 修改。
多语言:界面文字为中文,按钮文字可通过 confirmText / cancelText 修改,其余暂不支持。

收藏人数:
购买源码授权版(
试用
使用 HBuilder 导入示例项目
赞赏(0)
下载 1499
赞赏 0
下载 12760624
赞赏 1959
赞赏
京公网安备:11010802035340号