保存图片到系统相册
UNI
uni.saveImageToPhotosAlbum
语法
1
| uni.saveImageToPhotosAlbum(OBJECT);
|
平台差异说明
App | H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 抖音小程序、飞书小程序 | QQ 小程序 | 快手小程序 | 京东小程序 |
---|
√ | x | √ | √ | √ | √ | √ | √ | √ |
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 |
---|
filePath | String | 是 | 图片文件路径,可以是临时文件路径也可以是永久文件路径,不支持网络图片路径 |
success | Function | 否 | 接口调用成功的回调函数 |
fail | Function | 否 | 接口调用失败的回调函数 |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
success 返回参数说明
参数名 | 类型 | 说明 |
---|
path | String | 保存到相册的图片路径,仅 App 3.0.5+ 支持 |
errMsg | String | 调用结果 |
示例
1 2 3 4 5 6 7 8 9 10 11 12
| uni.chooseImage({ count: 1, sourceType: ["camera"], success: function (res) { uni.saveImageToPhotosAlbum({ filePath: res.tempFilePaths[0], success: function () { console.log("save success"); } }); } });
|
PLUS
H5 端可以使用 plus api 来将图片保存到相册
plus.gallery.save
语法
1
| plus.gallery.save(path, successCB, errorCB);
|
条件编译调用 HTML5+
在 uni-app 调用 HTML5+ 的扩展规范时,需要注意使用条件编译。否则运行到 h5、小程序等平台会出现 plus is not defined
错误。
1 2 3 4
| var appid = plus.runtime.appid; console.log("应用的 appid 为:" + appid);
|
说明
保存文件到系统相册中。 每次仅能保存一个文件,支持图片文件(jpg/jpeg、png、bmp 等格式)和视频文件(3gp、mov 等格式)。 若保存的文件类型当前系统不支持,则通过 errorCB 回调返回错误信息。
参数说明
参数名 | 类型 | 必填 | 说明 |
---|
path | String | 是 | 要保存到系统相册中的文件文件地址 |
succesCB | Function | 是 | 保存文件到系统相册中成功的回调函数 |
errorCB | Function | 否 | 保存文件到系统相册中失败的回调函数 |
平台支持
Android - 2.2+ (支持)
iOS - 4.3+ (支持)
示例
1 2 3 4 5 6
| function savePicture() { plus.gallery.save("_doc/a.jpg", function () { alert("保存图片到相册成功"); }); }
|
从相册中选择图片或视频文件
UNI
选择图片
从本地相册选择图片或使用相机拍照
uni.chooseImage
1
| uni.chooseImage(OBJECT);
|
参数说明
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|
count | Number | 否 | 最多可以选择的图片张数,默认 9 | 见下方说明 |
sizeType | Array | 否 | original 原图,compressed 压缩图,默认二者都有 | App、微信小程序、支付宝小程序、百度小程序 |
extension | Array | 否 | 根据文件拓展名过滤,每一项都不能是空字符串。默认不过滤。 | H5(HBuilder X2.9.9+) |
sourceType | Array | 否 | 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 | 图片的本地文件路径列表 |
tempFiles | Array | 图片的本地文件列表,每一项是一个 File 对象 |
File 对象结构如下
参数 | 类型 | 说明 |
---|
path | String | 本地文件路径 |
size | Number | 本地文件大小,单位:B |
name | String | 包含扩展名的文件名称,仅 H5 支持 |
type | String | 文件类型,仅 H5 支持 |
示例
1 2 3 4 5 6 7 8
| uni.chooseImage({ count: 6, sizeType: ["original", "compressed"], sourceType: ["album"], success(res) { console.log(res.tempFilePaths); } });
|
选择视频
拍摄视频或从手机相册中选视频,返回视频的临时文件路径
uni.chooseVideo
1
| uni.chooseVideo(OBJECT);
|
参数说明
OBJECT 参数说明
参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
---|
sourceType | Array | 否 | album 从相册选视频,camera 使用相机拍摄,默认为:[‘album’, ‘camera’] | |
extension | Array | 否 | 根据文件拓展名过滤,每一项都不能是空字符串。默认不过滤。 | H5(HBuilder X 2.9.9+) |
compressed | Boolean | 否 | 是否压缩所选的视频源文件,默认值为 true,需要压缩。 | 微信小程序、百度小程序、抖音小程序、飞书小程序、京东小程序、App(HBuilder X 3.2.7+) |
maxDuration | Number | 否 | 拍摄视频最长拍摄时间,单位秒。最长支持 60 秒。 | APP 平台 1.9.7+(iOS 支持,Android 取决于 ROM 的拍照组件是否实现此功能,如果没实现此功能则忽略此属性。) 微信小程序、百度小程序、京东小程序 |
camera | String | 否 | ‘front’、’back’,默认’back’ | APP、微信小程序、京东小程序 |
success | Function | 否 | 接口调用成功,返回视频文件的临时文件路径,详见返回参数说明。 | |
fail | Function | 否 | 接口调用失败的回调函数 | |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) | |
success 返回参数说明
参数 | 类型 | 说明 | 平台差异 |
---|
tempFilePath | String | 选定视频的临时文件路径 | |
tempFile | File | 选定的视频文件 | 仅 H5(2.6.15+)支持 |
duration | Number | 选定视频的时间长度,单位为 s | APP 2.1.0+、H5、微信小程序、京东小程序 |
size | Number | 选定视频的数据量大小 | APP 2.1.0+、H5、微信小程序、京东小程序 |
height | Number | 返回选定视频的高 | APP 2.1.0+、H5、微信小程序、京东小程序 |
width | Number | 返回选定视频的宽 | APP 2.1.0+、H5、微信小程序、京东小程序 |
name | String | 包含扩展名的文件名称 | 仅 H5 支持 |
PLUS
plus.gallery.pick
语法
1
| plus.gallery.pick(successCB, errorCB, options);
|
参数说明
参数名 | 类型 | 必填 | 说明 |
---|
options | GalleryOptions | 否 | 设置选择文件的参数 |
succesCB | Function | 是 | 保存文件到系统相册中成功的回调函数 |
errorCB | Function | 否 | 保存文件到系统相册中失败的回调函数 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| interface GalleryOptions { animation: Boolean; confirmText: String; crop: GalleryCropStyles; editable: Boolean; filename: String; filter: GalleryFilter; maximum: Number; multiple: Boolean; permissionAlert: Boolean; popover: PopPosition; selected: Array<String>; system: Boolean; onmaxed: Function; }
interface GalleryCropStyles { quality: Number; width: Number; height: Number; resize: Boolean; saveToAlbum: Boolean; }
type GalleryFilter = | "image" | "video" | "none";
interface PopPosition { top: String; left: String; width: String; height: String; }
|
平台支持
Android - 2.2+ (支持)
iOS - 5.1+ (支持)
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| export function galleryF(list) { if (!list.length) return;
const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i; const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i;
return list.map((url) => { return { url, type: IMAGE_REGEXP.test(url) ? "image" : VIDEO_REGEXP.test(url) ? "video" : "", name: url.slice(url.lastIndexOf("/") + 1) }; }); }
export function gallery(options = {}) { const { multiple = true, maximum = 9, filter = "none" } = options;
return new Promise((resolve, reject) => { plus.gallery.pick( (path) => { resolve(galleryF(path.files)); }, (error = "取消选择") => { reject(error); }, { multiple, maximum, filter, permissionAlert: true, onmaxed() { plus.nativeUI.alert(`最多只能选择${9}张`); } } ); }); }
|
获取父组件的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
export function $parent(name = undefined) { let parent = this.$parent; while (parent) { if (parent.$options && parent.$options.name !== name) { parent = parent.$parent; } else { return parent; } } return false; }
|
获取目标元素的节点布局信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
function uGetRect(selector, all) { return new Promise((resolve) => { uni .createSelectorQuery() .in(this) [all ? "selectAll" : "select"](selector) .boundingClientRect((rect) => { if (all && Array.isArray(rect) && rect.length) { resolve(rect); } if (!all && rect) { resolve(rect); } }) .exec(); }); }
|
获取用户传递值的 px 值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const isNumber = (v) => /^[+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(v);
function getPx(value, unit = false) { if (isNumber(value)) { return unit ? `${value}px` : Number(value); } if (/(rpx|upx)$/.test(value)) { return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value))); } return unit ? `${parseInt(value)}px` : parseInt(value); }
|
获取图片信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
function getImageInfo(filepath) { return new Promise(function (resolve, reject) { plus.io.getImageInfo({ src: filepath, success: function (image) { resolve(image); }, fail: function (err) { console.log("getImageInfoErr: " + JSON.stringify(err)); reject(err); } });
uni.getImageInfo({ src: filepath, success: function (image) { resolve(image); }, fail: function (err) { console.log("getImageInfoErr: " + JSON.stringify(err)); reject(err); } }); }); }
|
IO 操作
写入文件内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
export function fileWriter(filePath, content, position) { return new Promise((resolve, reject) => { plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function (fs) { fs.root.getFile( filePath, { create: true }, function (fileEntry) { fileEntry.createWriter( function (writer) { writer.seek(position == undefined ? writer.length : position); writer.write(content); resolve(writer); }, function (e) { console.error("本地文件日志写入异常", e); reject(); } ); } ); }); resolve(); }); }
|
读取文件内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
export function fileReader(filePath) { return new Promise((resolve, reject) => { plus.io.requestFileSystem(plus.io.PRIVATE_DOC, function (fs) { fs.root.getFile(filePath, {}, function (fileEntry) { fileEntry.file(function (file) { let fileReader = new plus.io.FileReader(); fileReader.readAsText(file, "utf-8"); fileReader.onloadend = function (evt) { const { result: content, error } = evt?.target || {}; if (error) { reject(); } else { resolve({ ...file, content }); } }; }); }); }); }); }
|
读取目录文件列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
export function fileList(filePath) { return new Promise((resolve, reject) => { plus.io.resolveLocalFileSystemURL( filePath, (entry) => { var directoryReader = entry.createReader(); directoryReader.readEntries( (entries) => { resolve(entries); }, (err) => { reject("读取失败"); console.error("读取本地目录", filePath, err); } ); }, (err) => { reject("读取失败"); console.error("读取本地目录", filePath, err); } ); }); }
|
读取目录文件列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
export async function fileListDeep(path) { return new Promise(async (resolve) => { let realFilesObj = {}; await innerCollect(path); async function innerCollect(path) { let realFiles = []; let logFolders = await fileList(`${path}`); for (let i = 0; i < logFolders.length; i++) { const file = logFolders[i]; if (file.isDirectory) { await innerCollect(file.toURL()); } else { realFiles.push(file); } } realFilesObj[path] = realFiles; return; } resolve(realFilesObj); }); }
|
压缩目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
export function zipPath(targetPath = "_doc/", name) { return new Promise((resolve, reject) => { let zipfile = `_documents/${ name || targetPath.replace(/_/g, "").replace(/\//g, "_") }${timeF("MMddhhmmssS")}.zip`; plus.zip.compress( targetPath, zipfile, () => { resolve({ filePath: plus.io.convertLocalFileSystemURL(zipfile), localFile: zipfile }); }, (error) => { reject(error); } ); }); }
|
删除单个文件或目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
export function removeFile(filePath, singleFile = false) { return new Promise((resolve, reject) => { plus.io.resolveLocalFileSystemURL( filePath, (entry) => {
entry[!singleFile ? "removeRecursively" : "remove"]( () => { console.log("success"); resolve(); }, () => { console.log("error"); reject(); } ); }, () => { reject(); } ); }); }
|
按条件删除文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
export function removeFileByOptions(files, options) { if (!options) { return removeFiles(files); } else { const { filter = (el) => ({ del: true }), retainMin = 0, sortMax = 0 } = options; return files .map((file) => { const { sort, del = false } = filter(file); if (del) { file.remove(); } return { file, sort, del }; }) .filter((item) => !item.del) .sort((a, b) => a.sort - b.sort) .filter((item, index, self) => { if (item.sort < sortMax && index < self.length - retainMin) { item.file.remove(); return false; } return true; }); } }
|
删除多个文件或目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
export function removeFiles(files = []) { return new Promise((resolve, reject) => { let filesLen = files?.length ?? 0; if (!filesLen) { resolve(); return; } for (let i = 0; i < filesLen; i++) { const file = files[i]; file.removeRecursively( () => { filesLen--; if (filesLen === 0) { resolve(); } }, (err) => { console.error("remove failed", file.name, err); reject(`删除失败:${err}`); } ); } }); }
|
未完,待续。。。