From 7427e2407e1ad0b853bbbfed3eeb6c4f53cc1121 Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Mon, 15 May 2023 17:13:00 +0800 Subject: [PATCH 1/9] =?UTF-8?q?feat(h5):=20=E6=94=AF=E6=8C=81=20chooseMedi?= =?UTF-8?q?a=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/media/image/chooseImage.ts | 16 ++- .../src/api/media/video/chooseMedia.ts | 108 ++++++++++++++++++ .../src/api/media/video/chooseVideo.ts | 73 ++++++++++++ packages/taro-h5/src/api/media/video/index.ts | 66 +---------- packages/taro-h5/src/api/share/index.ts | 24 +++- packages/taro/types/api/media/image.d.ts | 22 ++-- packages/taro/types/api/media/video.d.ts | 60 +++++++--- 7 files changed, 279 insertions(+), 90 deletions(-) create mode 100644 packages/taro-h5/src/api/media/video/chooseMedia.ts create mode 100644 packages/taro-h5/src/api/media/video/chooseVideo.ts diff --git a/packages/taro-h5/src/api/media/image/chooseImage.ts b/packages/taro-h5/src/api/media/image/chooseImage.ts index 1885347d85a3..c239fd85c822 100644 --- a/packages/taro-h5/src/api/media/image/chooseImage.ts +++ b/packages/taro-h5/src/api/media/image/chooseImage.ts @@ -16,12 +16,15 @@ export const chooseImage: typeof Taro.chooseImage = function (options) { } const { - count = 1, + count = 9, + imageId = 'taroChooseImage', + sourceType = ['album', 'camera'], + // TODO 考虑通过 ffmpeg 支持压缩 + // sizeType = ['original', 'compressed'], + // camera = 'back', success, fail, complete, - imageId = 'taroChooseImage', - sourceType = ['album', 'camera'] } = options const handle = new MethodHandler({ name: 'chooseImage', success, fail, complete }) const res: Partial = { @@ -84,7 +87,12 @@ export const chooseImage: typeof Taro.chooseImage = function (options) { }) const url = URL.createObjectURL(blob) res.tempFilePaths?.push(url) - res.tempFiles?.push({ path: url, size: item.size, type: item.type, originalFileObj: item }) + res.tempFiles?.push({ + path: url, + size: item.size, + type: item.type, + originalFileObj: item + }) }) handle.success(res, { resolve, reject }) target.value = '' diff --git a/packages/taro-h5/src/api/media/video/chooseMedia.ts b/packages/taro-h5/src/api/media/video/chooseMedia.ts new file mode 100644 index 000000000000..832815371c3e --- /dev/null +++ b/packages/taro-h5/src/api/media/video/chooseMedia.ts @@ -0,0 +1,108 @@ +import Taro from '@tarojs/api' + +import { getParameterError, shouldBeObject } from '../../../utils' +import { MethodHandler } from '../../../utils/handler' + +/** + * 拍摄或从手机相册中选择图片或视频。 + */ +export const chooseMedia: typeof Taro.chooseMedia = function (options) { + // options must be an Object + const isObject = shouldBeObject(options) + if (!isObject.flag) { + const res = { errMsg: `chooseMedia:fail ${isObject.msg}` } + console.error(res.errMsg) + return Promise.reject(res) + } + + const { + count = 9, + mediaId = 'taroChooseMedia', + // mediaType = ['image', 'video'], + sourceType = ['album', 'camera'], + // TODO 考虑通过 ffmpeg 支持压缩 + // sizeType = ['original', 'compressed'], + // maxDuration = 10, + // camera = 'back', + success, + fail, + complete, + } = options + const handle = new MethodHandler({ name: 'chooseMedia', success, fail, complete }) + const res: Partial = { + tempFiles: [], + type: ' mix', + } + const sourceTypeString = sourceType && sourceType.toString() + const acceptableSourceType = ['user', 'environment', 'camera'] + + if (count && typeof count !== 'number') { + res.errMsg = getParameterError({ + para: 'count', + correct: 'Number', + wrong: count + }) + return handle.fail(res) + } + + let el = document.getElementById(mediaId) + if (!el) { + const obj = document.createElement('input') + obj.setAttribute('type', 'file') + obj.setAttribute('id', mediaId) + if (count > 1) { + obj.setAttribute('multiple', 'multiple') + } + if (acceptableSourceType.indexOf(sourceTypeString) > -1) { + obj.setAttribute('capture', sourceTypeString) + } + obj.setAttribute('accept', 'image/*') + obj.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') + document.body.appendChild(obj) + el = document.getElementById(mediaId) + } else { + if (count > 1) { + el.setAttribute('multiple', 'multiple') + } else { + el.removeAttribute('multiple') + } + if (acceptableSourceType.indexOf(sourceTypeString) > -1) { + el.setAttribute('capture', sourceTypeString) + } else { + el.removeAttribute('capture') + } + } + + return new Promise((resolve, reject) => { + const TaroMouseEvents = document.createEvent('MouseEvents') + TaroMouseEvents.initEvent('click', true, true) + if (el) { + el.dispatchEvent(TaroMouseEvents) + el.onchange = function (e) { + const target = e.target as HTMLInputElement + if (target) { + const files = target.files || [] + const arr = [...files] + arr && arr.forEach(item => { + const blob = new Blob([item], { + type: item.type + }) + const url = URL.createObjectURL(blob) + res.tempFiles?.push({ + tempFilePath: url, + size: item.size, + duration: 0, + height: 0, + width: 0, + thumbTempFilePath: '', + fileType: item.type, + originalFileObj: item + }) + }) + handle.success(res, { resolve, reject }) + target.value = '' + } + } + } + }) +} diff --git a/packages/taro-h5/src/api/media/video/chooseVideo.ts b/packages/taro-h5/src/api/media/video/chooseVideo.ts new file mode 100644 index 000000000000..a58b47a3749d --- /dev/null +++ b/packages/taro-h5/src/api/media/video/chooseVideo.ts @@ -0,0 +1,73 @@ +import Taro from '@tarojs/api' + +import { shouldBeObject } from '../../../utils' +import { MethodHandler } from '../../../utils/handler' + +/** + * 拍摄视频或从手机相册中选视频。 + */ +export const chooseVideo: typeof Taro.chooseVideo = (options) => { + // options must be an Object + const isObject = shouldBeObject(options) + if (!isObject.flag) { + const res = { errMsg: `chooseVideo:fail ${isObject.msg}` } + console.error(res.errMsg) + return Promise.reject(res) + } + + const { + // sourceType = ['album', 'camera'], + // TODO 考虑通过 ffmpeg 支持压缩 + // compressed = true, + // maxDuration = 60, + // camera = 'back', + success, + fail, + complete, + } = options + const handle = new MethodHandler({ name: 'chooseVideo', success, fail, complete }) + const res: Partial = { + tempFilePath: '', + duration: 0, + size: 0, + height: 0, + width: 0 + } + + const inputEl = document.createElement('input') + inputEl.setAttribute('type', 'file') + inputEl.setAttribute('multiple', 'multiple') + inputEl.setAttribute('accept', 'video/*') + inputEl.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') + document.body.appendChild(inputEl) + + return new Promise((resolve, reject) => { + const TaroMouseEvents = document.createEvent('MouseEvents') + TaroMouseEvents.initEvent('click', true, true) + inputEl.dispatchEvent(TaroMouseEvents) + inputEl.onchange = function (e) { + const target = e.target as HTMLInputElement + const file = target.files?.[0] + const reader = new FileReader() + reader.onload = function (event: ProgressEvent) { + const videoEl = document.createElement('video') + const url = event.target?.result as string + videoEl.preload = 'metadata' + videoEl.src = url + videoEl.onloadedmetadata = () => { + res.tempFilePath = url + res.duration = videoEl.duration + res.size = event.total + res.height = videoEl.videoHeight + res.width = videoEl.videoHeight + return handle.success(res, { resolve, reject }) + } + } + if (file) { + reader.readAsDataURL(file) + } + } + }).finally(() => { + document.body.removeChild(inputEl) + }) +} diff --git a/packages/taro-h5/src/api/media/video/index.ts b/packages/taro-h5/src/api/media/video/index.ts index 38291353e8f1..f3b590136790 100644 --- a/packages/taro-h5/src/api/media/video/index.ts +++ b/packages/taro-h5/src/api/media/video/index.ts @@ -1,7 +1,6 @@ import Taro from '@tarojs/api' -import { findDOM, shouldBeObject, temporarilyNotSupport } from '../../../utils' -import { MethodHandler } from '../../../utils/handler' +import { findDOM, temporarilyNotSupport } from '../../../utils' // 视频 export const saveVideoToPhotosAlbum = temporarilyNotSupport('saveVideoToPhotosAlbum') @@ -19,64 +18,5 @@ export const createVideoContext: typeof Taro.createVideoContext = (id, inst) => export const compressVideo = temporarilyNotSupport('compressVideo') -/** - * 拍摄视频或从手机相册中选视频。 - */ -export const chooseVideo: typeof Taro.chooseVideo = (options) => { - // options must be an Object - const isObject = shouldBeObject(options) - if (!isObject.flag) { - const res = { errMsg: `chooseVideo:fail ${isObject.msg}` } - console.error(res.errMsg) - return Promise.reject(res) - } - - const { success, fail, complete } = options - const handle = new MethodHandler({ name: 'chooseVideo', success, fail, complete }) - const res: Partial = { - tempFilePath: '', - duration: 0, - size: 0, - height: 0, - width: 0 - } - - const inputEl = document.createElement('input') - inputEl.setAttribute('type', 'file') - inputEl.setAttribute('multiple', 'multiple') - inputEl.setAttribute('accept', 'video/*') - inputEl.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') - document.body.appendChild(inputEl) - - return new Promise((resolve, reject) => { - const TaroMouseEvents = document.createEvent('MouseEvents') - TaroMouseEvents.initEvent('click', true, true) - inputEl.dispatchEvent(TaroMouseEvents) - inputEl.onchange = function (e) { - const target = e.target as HTMLInputElement - const file = target.files?.[0] - const reader = new FileReader() - reader.onload = function (event: ProgressEvent) { - const videoEl = document.createElement('video') - const url = event.target?.result as string - videoEl.preload = 'metadata' - videoEl.src = url - videoEl.onloadedmetadata = () => { - res.tempFilePath = url - res.duration = videoEl.duration - res.size = event.total - res.height = videoEl.videoHeight - res.width = videoEl.videoHeight - return handle.success(res, { resolve, reject }) - } - } - if (file) { - reader.readAsDataURL(file) - } - } - }).finally(() => { - document.body.removeChild(inputEl) - }) -} - -export const chooseMedia = temporarilyNotSupport('chooseMedia') +export * from './chooseMedia' +export * from './chooseVideo' diff --git a/packages/taro-h5/src/api/share/index.ts b/packages/taro-h5/src/api/share/index.ts index 2961ae10f8a2..a0814bf187e9 100644 --- a/packages/taro-h5/src/api/share/index.ts +++ b/packages/taro-h5/src/api/share/index.ts @@ -1,13 +1,33 @@ -import { temporarilyNotSupport } from '../../utils' +import { permanentlyNotSupport,temporarilyNotSupport } from '../../utils' // 转发 + +/** 更新转发属性 */ export const updateShareMenu = temporarilyNotSupport('updateShareMenu') + +/** 显示当前页面的转发按钮 */ export const showShareMenu = temporarilyNotSupport('showShareMenu') + +/** 打开分享图片弹窗,可以将图片发送给朋友、收藏或下载 */ export const showShareImageMenu = temporarilyNotSupport('showShareImageMenu') + +/** 转发视频到聊天 */ export const shareVideoMessage = temporarilyNotSupport('shareVideoMessage') + +/** 转发文件到聊天 */ export const shareFileMessage = temporarilyNotSupport('shareFileMessage') + +/** 监听用户点击右上角菜单的「复制链接」按钮时触发的事件 */ export const onCopyUrl = temporarilyNotSupport('onCopyUrl') + +/** 移除用户点击右上角菜单的「复制链接」按钮时触发的事件的监听函数 */ export const offCopyUrl = temporarilyNotSupport('offCopyUrl') + +/** 隐藏当前页面的转发按钮 */ export const hideShareMenu = temporarilyNotSupport('hideShareMenu') + +/** 获取转发详细信息 */ export const getShareInfo = temporarilyNotSupport('getShareInfo') -export const authPrivateMessage = temporarilyNotSupport('authPrivateMessage') + +/** 验证私密消息。 */ +export const authPrivateMessage = permanentlyNotSupport('authPrivateMessage') diff --git a/packages/taro/types/api/media/image.d.ts b/packages/taro/types/api/media/image.d.ts index 788e42ce58c5..0ff90e160e06 100644 --- a/packages/taro/types/api/media/image.d.ts +++ b/packages/taro/types/api/media/image.d.ts @@ -127,19 +127,27 @@ declare module '../../index' { namespace chooseImage { interface Option { + /** 最多可以选择的图片张数 + * @default 9 + */ + count?: number + /** 所选的图片的尺寸 + * @default ['original', 'compressed'] + */ + sizeType?: Array + /** 选择图片的来源 + * @default ['album', 'camera'] + */ + sourceType?: Array /** 接口调用结束的回调函数(调用成功、失败都会执行) */ complete?: (res: TaroGeneral.CallbackResult) => void - /** 最多可以选择的图片张数 */ - count?: number /** 接口调用失败的回调函数 */ fail?: (res: TaroGeneral.CallbackResult) => void - /** 所选的图片的尺寸 */ - sizeType?: Array - /** 选择图片的来源 */ - sourceType?: Array /** 接口调用成功的回调函数 */ success?: (result: SuccessCallbackResult) => void - /** 用来上传的input元素ID(仅h5端)@supported h5 */ + /** 用来上传的input元素ID(仅h5端 + * @supported h5 + */ imageId?: string } /** 图片的尺寸 */ diff --git a/packages/taro/types/api/media/video.d.ts b/packages/taro/types/api/media/video.d.ts index 2cc2db27c786..719f52ce7148 100644 --- a/packages/taro/types/api/media/video.d.ts +++ b/packages/taro/types/api/media/video.d.ts @@ -233,18 +233,26 @@ declare module '../../index' { namespace chooseVideo { interface Option { - /** 默认拉起的是前置或者后置摄像头。部分 Android 手机下由于系统 ROM 不支持无法生效 */ + /** 默认拉起的是前置或者后置摄像头。部分 Android 手机下由于系统 ROM 不支持无法生效 + * @default "back" + */ camera?: keyof Camera + /** 是否压缩所选择的视频文件 + * @default true + */ + compressed?: boolean + /** 拍摄视频最长拍摄时间,单位秒 + * @default 60 + */ + maxDuration?: number + /** 视频选择的来源 + * @default ['album', 'camera'] + */ + sourceType?: Array /** 接口调用结束的回调函数(调用成功、失败都会执行) */ complete?: (res: TaroGeneral.CallbackResult) => void - /** 是否压缩所选择的视频文件 */ - compressed?: boolean /** 接口调用失败的回调函数 */ fail?: (res: TaroGeneral.CallbackResult) => void - /** 拍摄视频最长拍摄时间,单位秒 */ - maxDuration?: number - /** 视频选择的来源 */ - sourceType?: Array /** 接口调用成功的回调函数 */ success?: (result: SuccessCallbackResult) => void } @@ -279,27 +287,45 @@ declare module '../../index' { namespace chooseMedia { interface Option { - /** 最多可以选择的文件个数 */ + /** 最多可以选择的文件个数 + * @default 9 + */ count?: number - /** 文件类型 */ + /** 文件类型 + * @default ['image', 'video'] + */ mediaType?: Array - /** 图片和视频选择的来源 */ + /** 图片和视频选择的来源 + * @default ['album', 'camera'] + */ sourceType?: Array - /** 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 30s 之间 */ + /** 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 60s 之间 + * @default 10 + */ maxDuration?: number - /** 仅对 mediaType 为 image 时有效,是否压缩所选文件 */ + /** 仅对 mediaType 为 image 时有效,是否压缩所选文件 + * @default ['original', 'compressed'] + */ sizeType?: Array<'original' | 'compressed'> - /** 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 */ + /** 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 + * @default "back" + */ camera?: string + /** 接口调用结束的回调函数(调用成功、失败都会执行) */ + complete?: (res: TaroGeneral.CallbackResult) => void /** 接口调用失败的回调函数 */ fail?: (res: TaroGeneral.CallbackResult) => void /** 接口调用成功的回调函数 */ success?: (result: SuccessCallbackResult) => void + /** 用来上传的input元素ID + * @supported h5 + */ + mediaId?: string } interface SuccessCallbackResult extends TaroGeneral.CallbackResult { /** 本地临时文件列表 */ tempFiles: ChooseMedia[] - /** 文件类型,有效值有 image 、video */ + /** 文件类型,有效值有 image 、video、mix */ type: string } /** 本地临时文件列表 */ @@ -316,6 +342,12 @@ declare module '../../index' { width: number /** 视频缩略图临时文件路径 */ thumbTempFilePath: string + /** 选择的文件的类型 */ + fileType: string + /** 原始的浏览器 File 对象 + * @supported h5 + */ + originalFileObj?: File } interface mediaType { /** 只能拍摄视频或从相册选择视频 */ From 2290894724b6747d074ad0025f9886470ff5bdbf Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Tue, 16 May 2023 14:15:49 +0800 Subject: [PATCH 2/9] =?UTF-8?q?feat(h5):=20=E7=BB=9F=E4=B8=80=20chooseMedi?= =?UTF-8?q?a=20=E6=96=B9=E6=B3=95=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/media/image/chooseImage.ts | 114 ++++-------- .../src/api/media/video/chooseMedia.ts | 163 ++++++++++++------ .../src/api/media/video/chooseVideo.ts | 72 +++----- packages/taro-h5/src/utils/constants.ts | 2 + packages/taro/types/api/media/video.d.ts | 13 +- 5 files changed, 172 insertions(+), 192 deletions(-) create mode 100644 packages/taro-h5/src/utils/constants.ts diff --git a/packages/taro-h5/src/api/media/image/chooseImage.ts b/packages/taro-h5/src/api/media/image/chooseImage.ts index c239fd85c822..faf4d2d2b23f 100644 --- a/packages/taro-h5/src/api/media/image/chooseImage.ts +++ b/packages/taro-h5/src/api/media/image/chooseImage.ts @@ -1,103 +1,51 @@ import Taro from '@tarojs/api' -import { getParameterError, shouldBeObject } from '../../../utils' -import { MethodHandler } from '../../../utils/handler' +import { shouldBeObject } from '../../../utils' +import { chooseMedia } from '../video' /** * 从本地相册选择图片或使用相机拍照。 + * @deprecated 请使用 chooseMedia 接口 */ export const chooseImage: typeof Taro.chooseImage = function (options) { // options must be an Object const isObject = shouldBeObject(options) if (!isObject.flag) { - const res = { errMsg: `chooseImage:fail ${isObject.msg}` } + const res = { errMsg: `${chooseImage.name}:fail ${isObject.msg}` } console.error(res.errMsg) return Promise.reject(res) } - const { - count = 9, - imageId = 'taroChooseImage', - sourceType = ['album', 'camera'], - // TODO 考虑通过 ffmpeg 支持压缩 - // sizeType = ['original', 'compressed'], - // camera = 'back', - success, - fail, - complete, - } = options - const handle = new MethodHandler({ name: 'chooseImage', success, fail, complete }) - const res: Partial = { - tempFilePaths: [], - tempFiles: [] - } - const sourceTypeString = sourceType && sourceType.toString() - const acceptableSourceType = ['user', 'environment', 'camera'] - - if (count && typeof count !== 'number') { - res.errMsg = getParameterError({ - para: 'count', - correct: 'Number', - wrong: count - }) - return handle.fail(res) + let camera = 'back' + const { sourceType = [], success, complete, ...args } = options + if (sourceType.includes('camera') && sourceType.indexOf('user') > -1) { + camera = 'front' } - let el = document.getElementById(imageId) - if (!el) { - const obj = document.createElement('input') - obj.setAttribute('type', 'file') - obj.setAttribute('id', imageId) - if (count > 1) { - obj.setAttribute('multiple', 'multiple') - } - if (acceptableSourceType.indexOf(sourceTypeString) > -1) { - obj.setAttribute('capture', sourceTypeString) - } - obj.setAttribute('accept', 'image/*') - obj.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') - document.body.appendChild(obj) - el = document.getElementById(imageId) - } else { - if (count > 1) { - el.setAttribute('multiple', 'multiple') - } else { - el.removeAttribute('multiple') - } - if (acceptableSourceType.indexOf(sourceTypeString) > -1) { - el.setAttribute('capture', sourceTypeString) - } else { - el.removeAttribute('capture') + function parseRes (res: Taro.chooseMedia.SuccessCallbackResult): Taro.chooseImage.SuccessCallbackResult { + const { tempFiles = [], errMsg } = res + return { + tempFilePaths: tempFiles.map(item => item.tempFilePath), + tempFiles: tempFiles.map(item => ({ + path: item.tempFilePath, + size: item.size, + type: item.fileType, + originalFileObj: item.originalFileObj, + })), + errMsg, } } - return new Promise((resolve, reject) => { - const TaroMouseEvents = document.createEvent('MouseEvents') - TaroMouseEvents.initEvent('click', true, true) - if (el) { - el.dispatchEvent(TaroMouseEvents) - el.onchange = function (e) { - const target = e.target as HTMLInputElement - if (target) { - const files = target.files || [] - const arr = [...files] - arr && arr.forEach(item => { - const blob = new Blob([item], { - type: item.type - }) - const url = URL.createObjectURL(blob) - res.tempFilePaths?.push(url) - res.tempFiles?.push({ - path: url, - size: item.size, - type: item.type, - originalFileObj: item - }) - }) - handle.success(res, { resolve, reject }) - target.value = '' - } - } - } - }) + return chooseMedia({ + mediaId: 'taroChooseImage', + ...args, + sourceType: sourceType as Taro.chooseMedia.Option['sourceType'], + camera, + success: (res) => { + const param = parseRes(res) + success?.(param) + complete?.(param) + }, + complete, + }, chooseImage.name).then(parseRes) } diff --git a/packages/taro-h5/src/api/media/video/chooseMedia.ts b/packages/taro-h5/src/api/media/video/chooseMedia.ts index 832815371c3e..b33c0341d486 100644 --- a/packages/taro-h5/src/api/media/video/chooseMedia.ts +++ b/packages/taro-h5/src/api/media/video/chooseMedia.ts @@ -1,16 +1,20 @@ import Taro from '@tarojs/api' import { getParameterError, shouldBeObject } from '../../../utils' +import { REG_MEDIA } from '../../../utils/constants' import { MethodHandler } from '../../../utils/handler' /** * 拍摄或从手机相册中选择图片或视频。 */ -export const chooseMedia: typeof Taro.chooseMedia = function (options) { +export const chooseMedia = function ( + options: Taro.chooseMedia.Option, + methodName = chooseMedia.name, +): Promise { // options must be an Object const isObject = shouldBeObject(options) if (!isObject.flag) { - const res = { errMsg: `chooseMedia:fail ${isObject.msg}` } + const res = { errMsg: `${methodName}:fail ${isObject.msg}` } console.error(res.errMsg) return Promise.reject(res) } @@ -18,23 +22,22 @@ export const chooseMedia: typeof Taro.chooseMedia = function (options) { const { count = 9, mediaId = 'taroChooseMedia', - // mediaType = ['image', 'video'], + mediaType = ['image', 'video'], sourceType = ['album', 'camera'], - // TODO 考虑通过 ffmpeg 支持压缩 - // sizeType = ['original', 'compressed'], - // maxDuration = 10, - // camera = 'back', + // sizeType = ['original', 'compressed'], // TODO 考虑通过 ffmpeg 支持压缩 + // maxDuration = 10, // TODO 考虑通过 ffmpeg 剪裁视频 + camera = 'back', success, fail, complete, } = options - const handle = new MethodHandler({ name: 'chooseMedia', success, fail, complete }) + const handle = new MethodHandler({ name: methodName, success, fail, complete }) + const withImage = mediaType.length < 1 || mediaType.indexOf('image') > -1 + const withVideo = mediaType.length < 1 || mediaType.indexOf('video') > -1 const res: Partial = { tempFiles: [], - type: ' mix', + type: withImage && withVideo ? 'mix' : withImage ? 'image' : 'video', } - const sourceTypeString = sourceType && sourceType.toString() - const acceptableSourceType = ['user', 'environment', 'camera'] if (count && typeof count !== 'number') { res.errMsg = getParameterError({ @@ -47,62 +50,114 @@ export const chooseMedia: typeof Taro.chooseMedia = function (options) { let el = document.getElementById(mediaId) if (!el) { - const obj = document.createElement('input') - obj.setAttribute('type', 'file') - obj.setAttribute('id', mediaId) - if (count > 1) { - obj.setAttribute('multiple', 'multiple') - } - if (acceptableSourceType.indexOf(sourceTypeString) > -1) { - obj.setAttribute('capture', sourceTypeString) - } - obj.setAttribute('accept', 'image/*') - obj.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') - document.body.appendChild(obj) - el = document.getElementById(mediaId) + el = document.createElement(mediaId) + el.setAttribute('type', 'file') + el.setAttribute('id', mediaId) + el.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') + } + + if (count > 1) { + el.setAttribute('multiple', 'multiple') } else { - if (count > 1) { - el.setAttribute('multiple', 'multiple') - } else { - el.removeAttribute('multiple') - } - if (acceptableSourceType.indexOf(sourceTypeString) > -1) { - el.setAttribute('capture', sourceTypeString) - } else { - el.removeAttribute('capture') - } + el.removeAttribute('multiple') + } + + // Note: Input 仅在移动端支持 capture 属性,可以使用 getUserMedia 替代(暂不考虑) + // FIXME sourceType 有多个值时,判断在移动端,提示用户选择【拍摄、从相册选择】 + if (sourceType.includes('camera')) { + el.setAttribute('capture', camera === 'front' ? 'user' : 'environment') + } else { + el.removeAttribute('capture') } - return new Promise((resolve, reject) => { + if (res.type === 'image') { + el.setAttribute('accept', 'image/*') + } else if (res.type === 'video') { + el.setAttribute('accept', 'video/*') + } else { + el.setAttribute('accept', 'image/*, video/*') + } + document.body.appendChild(el) + + return new Promise((resolve, reject) => { const TaroMouseEvents = document.createEvent('MouseEvents') TaroMouseEvents.initEvent('click', true, true) if (el) { el.dispatchEvent(TaroMouseEvents) - el.onchange = function (e) { + el.onchange = async function (e) { const target = e.target as HTMLInputElement if (target) { - const files = target.files || [] + const files = target.files || [] // name webkitRelativePath type const arr = [...files] - arr && arr.forEach(item => { - const blob = new Blob([item], { - type: item.type - }) - const url = URL.createObjectURL(blob) - res.tempFiles?.push({ - tempFilePath: url, - size: item.size, - duration: 0, - height: 0, - width: 0, - thumbTempFilePath: '', - fileType: item.type, - originalFileObj: item + await Promise.all( + arr.map(async item => { + try { + res.tempFiles?.push(await loadMedia(item)) + } catch (error) { + console.error(error) + } }) - }) - handle.success(res, { resolve, reject }) - target.value = '' + ) } + handle.success(res, { resolve, reject }) + target.value = '' } } + }).finally(() => { + el && document.body.removeChild(el) }) + + function loadMedia (file: File): Promise { + const dataUrl = URL.createObjectURL(file) + const res = { + tempFilePath: dataUrl, + size: file.size, + duration: 0, + height: 0, + width: 0, + thumbTempFilePath: '', + fileType: file.type, + originalFileObj: file + } + + if (REG_MEDIA.test(res.fileType)) { + // Video + const reader = new FileReader() + const vEl = document.createElement('video') + vEl.preload = 'metadata' + vEl.src = res.tempFilePath + + return new Promise((resolve, reject) => { + reader.onload = function () { + vEl.onloadedmetadata = () => { + res.duration = vEl.duration + res.height = vEl.height + res.width = vEl.width + resolve(res) + } + } + reader.onerror = e => reject(e) + reader.readAsDataURL(res.originalFileObj) + }) + } else { + // Image + const img = new Image() + img.src = res.tempFilePath + + return new Promise((resolve, reject) => { + if (img.complete) { + res.height = img.height + res.width = img.width + resolve(res) + } else { + img.onload = () => { + res.height = img.height + res.width = img.width + resolve(res) + } + img.onerror = e => reject(e) + } + }) + } + } } diff --git a/packages/taro-h5/src/api/media/video/chooseVideo.ts b/packages/taro-h5/src/api/media/video/chooseVideo.ts index a58b47a3749d..8c466f02d0d1 100644 --- a/packages/taro-h5/src/api/media/video/chooseVideo.ts +++ b/packages/taro-h5/src/api/media/video/chooseVideo.ts @@ -1,73 +1,49 @@ import Taro from '@tarojs/api' import { shouldBeObject } from '../../../utils' -import { MethodHandler } from '../../../utils/handler' +import { chooseMedia } from './chooseMedia' /** * 拍摄视频或从手机相册中选视频。 + * @deprecated 请使用 chooseMedia 接口 */ export const chooseVideo: typeof Taro.chooseVideo = (options) => { // options must be an Object const isObject = shouldBeObject(options) if (!isObject.flag) { - const res = { errMsg: `chooseVideo:fail ${isObject.msg}` } + const res = { errMsg: `${chooseVideo.name}:fail ${isObject.msg}` } console.error(res.errMsg) return Promise.reject(res) } const { - // sourceType = ['album', 'camera'], + sourceType = ['album', 'camera'], // TODO 考虑通过 ffmpeg 支持压缩 // compressed = true, - // maxDuration = 60, - // camera = 'back', + maxDuration = 60, + camera = 'back', success, fail, complete, } = options - const handle = new MethodHandler({ name: 'chooseVideo', success, fail, complete }) - const res: Partial = { - tempFilePath: '', - duration: 0, - size: 0, - height: 0, - width: 0 - } - const inputEl = document.createElement('input') - inputEl.setAttribute('type', 'file') - inputEl.setAttribute('multiple', 'multiple') - inputEl.setAttribute('accept', 'video/*') - inputEl.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') - document.body.appendChild(inputEl) + function parseRes (res: Taro.chooseMedia.SuccessCallbackResult): Taro.chooseVideo.SuccessCallbackResult { + const { tempFiles = [], errMsg } = res + const [video] = tempFiles + return { ...video, errMsg } + } - return new Promise((resolve, reject) => { - const TaroMouseEvents = document.createEvent('MouseEvents') - TaroMouseEvents.initEvent('click', true, true) - inputEl.dispatchEvent(TaroMouseEvents) - inputEl.onchange = function (e) { - const target = e.target as HTMLInputElement - const file = target.files?.[0] - const reader = new FileReader() - reader.onload = function (event: ProgressEvent) { - const videoEl = document.createElement('video') - const url = event.target?.result as string - videoEl.preload = 'metadata' - videoEl.src = url - videoEl.onloadedmetadata = () => { - res.tempFilePath = url - res.duration = videoEl.duration - res.size = event.total - res.height = videoEl.videoHeight - res.width = videoEl.videoHeight - return handle.success(res, { resolve, reject }) - } - } - if (file) { - reader.readAsDataURL(file) - } - } - }).finally(() => { - document.body.removeChild(inputEl) - }) + return chooseMedia({ + mediaId: 'taroChooseVideo', + sourceType, + maxDuration, + camera, + success: (res) => { + const param = parseRes(res) + success?.(param) + complete?.(param) + }, + fail, + complete, + }, chooseVideo.name).then(parseRes) } diff --git a/packages/taro-h5/src/utils/constants.ts b/packages/taro-h5/src/utils/constants.ts new file mode 100644 index 000000000000..d81db150fac0 --- /dev/null +++ b/packages/taro-h5/src/utils/constants.ts @@ -0,0 +1,2 @@ +export const REG_MEDIA = /\.(mp4|webm|ogg|mp3|m4a|wav|flac|aac)(\?.*)?$/ +export const REG_IMAGE = /\.(png|jpe?g|gif|bpm|svg|webp)(\?.*)?$/ diff --git a/packages/taro/types/api/media/video.d.ts b/packages/taro/types/api/media/video.d.ts index 719f52ce7148..ddcf1f7f81c1 100644 --- a/packages/taro/types/api/media/video.d.ts +++ b/packages/taro/types/api/media/video.d.ts @@ -257,14 +257,14 @@ declare module '../../index' { success?: (result: SuccessCallbackResult) => void } interface SuccessCallbackResult extends TaroGeneral.CallbackResult { + /** 选定视频的临时文件路径 */ + tempFilePath: string /** 选定视频的时间长度 */ duration: number - /** 返回选定视频的高度 */ - height: number /** 选定视频的数据量大小 */ size: number - /** 选定视频的临时文件路径 */ - tempFilePath: string + /** 返回选定视频的高度 */ + height: number /** 返回选定视频的宽度 */ width: number /** 调用结果 */ @@ -284,7 +284,6 @@ declare module '../../index' { } } - namespace chooseMedia { interface Option { /** 最多可以选择的文件个数 @@ -303,7 +302,7 @@ declare module '../../index' { * @default 10 */ maxDuration?: number - /** 仅对 mediaType 为 image 时有效,是否压缩所选文件 + /** 是否压缩所选文件 * @default ['original', 'compressed'] */ sizeType?: Array<'original' | 'compressed'> @@ -382,7 +381,7 @@ declare module '../../index' { * @example ```tsx * Taro.saveVideoToPhotosAlbum({ - * filePath: 'wxfile://xxx', + * filePath: 'file://xxx', * success: function (res) { * console.log(res.errMsg) * } From e8d51a009d9e8b1d668b1336e90780216acdc014 Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Tue, 16 May 2023 15:12:04 +0800 Subject: [PATCH 3/9] =?UTF-8?q?feat(h5):=20=E6=94=AF=E6=8C=81=20thumb=20te?= =?UTF-8?q?mp=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/media/video/chooseMedia.ts | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/packages/taro-h5/src/api/media/video/chooseMedia.ts b/packages/taro-h5/src/api/media/video/chooseMedia.ts index b33c0341d486..d63e4e5b0de6 100644 --- a/packages/taro-h5/src/api/media/video/chooseMedia.ts +++ b/packages/taro-h5/src/api/media/video/chooseMedia.ts @@ -123,16 +123,17 @@ export const chooseMedia = function ( if (REG_MEDIA.test(res.fileType)) { // Video const reader = new FileReader() - const vEl = document.createElement('video') - vEl.preload = 'metadata' - vEl.src = res.tempFilePath + const video = document.createElement('video') + video.preload = 'metadata' + video.src = res.tempFilePath return new Promise((resolve, reject) => { reader.onload = function () { - vEl.onloadedmetadata = () => { - res.duration = vEl.duration - res.height = vEl.height - res.width = vEl.width + video.onloadedmetadata = async () => { + res.duration = video.duration + res.height = video.videoHeight + res.width = video.videoWidth + res.thumbTempFilePath = getThumbTempFilePath(video, res.height, res.width, 0.8) resolve(res) } } @@ -142,17 +143,23 @@ export const chooseMedia = function ( } else { // Image const img = new Image() + /** 允许图片和 canvas 跨源使用 + * https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_enabled_image + */ + img.crossOrigin = 'Anonymous' img.src = res.tempFilePath return new Promise((resolve, reject) => { if (img.complete) { res.height = img.height res.width = img.width + res.thumbTempFilePath = getThumbTempFilePath(img, res.height, res.width, 0.8) resolve(res) } else { img.onload = () => { res.height = img.height res.width = img.width + res.thumbTempFilePath = getThumbTempFilePath(img, res.height, res.width, 0.8) resolve(res) } img.onerror = e => reject(e) @@ -160,4 +167,25 @@ export const chooseMedia = function ( }) } } + + function getThumbTempFilePath (el: CanvasImageSource, height = 0, width = height, quality = 0.8) { + const max = 256 + const canvas = document.createElement('canvas') + if (height > max || width > max) { + const radio = height / width + if (radio > 1) { + height = max + width = height / radio + } else { + width = max + height = width * radio + } + } + canvas.height = height + canvas.width = width + + const ctx = canvas.getContext('2d') + ctx?.drawImage(el, 0, 0, canvas.width, canvas.height) + return canvas.toDataURL('image/jpeg', quality) + } } From d300d631fee2360640aa4366424c10d4a4fbdf23 Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Tue, 16 May 2023 17:06:13 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat(h5):=20=E7=A7=BB=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=94=A8=E6=88=B7=E9=80=89=E6=8B=A9=20media?= =?UTF-8?q?=20=E4=BB=8E=E7=9B=B8=E5=86=8C=E3=80=81=E6=91=84=E5=83=8F?= =?UTF-8?q?=E5=A4=B4=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/media/image/chooseImage.ts | 14 +++- .../src/api/media/video/chooseMedia.ts | 70 ++++++++++++------- .../src/api/media/video/chooseVideo.ts | 7 +- .../taro-h5/src/api/ui/interaction/index.ts | 17 +++-- 4 files changed, 70 insertions(+), 38 deletions(-) diff --git a/packages/taro-h5/src/api/media/image/chooseImage.ts b/packages/taro-h5/src/api/media/image/chooseImage.ts index faf4d2d2b23f..78c1e9cb6dcc 100644 --- a/packages/taro-h5/src/api/media/image/chooseImage.ts +++ b/packages/taro-h5/src/api/media/image/chooseImage.ts @@ -17,7 +17,13 @@ export const chooseImage: typeof Taro.chooseImage = function (options) { } let camera = 'back' - const { sourceType = [], success, complete, ...args } = options + const { + sourceType = ['album', 'camera'], + success, + complete, + fail, + ...args + } = options if (sourceType.includes('camera') && sourceType.indexOf('user') > -1) { camera = 'front' } @@ -40,12 +46,16 @@ export const chooseImage: typeof Taro.chooseImage = function (options) { mediaId: 'taroChooseImage', ...args, sourceType: sourceType as Taro.chooseMedia.Option['sourceType'], + mediaType: ['image'], camera, success: (res) => { const param = parseRes(res) success?.(param) complete?.(param) }, - complete, + fail: (err) => { + fail?.(err) + complete?.(err) + }, }, chooseImage.name).then(parseRes) } diff --git a/packages/taro-h5/src/api/media/video/chooseMedia.ts b/packages/taro-h5/src/api/media/video/chooseMedia.ts index d63e4e5b0de6..d6022c6eb496 100644 --- a/packages/taro-h5/src/api/media/video/chooseMedia.ts +++ b/packages/taro-h5/src/api/media/video/chooseMedia.ts @@ -1,5 +1,7 @@ import Taro from '@tarojs/api' +import { getMobileDetect } from '@tarojs/router/dist/utils/navigate' +import { showActionSheet } from '../../../api/ui' import { getParameterError, shouldBeObject } from '../../../utils' import { REG_MEDIA } from '../../../utils/constants' import { MethodHandler } from '../../../utils/handler' @@ -7,7 +9,7 @@ import { MethodHandler } from '../../../utils/handler' /** * 拍摄或从手机相册中选择图片或视频。 */ -export const chooseMedia = function ( +export const chooseMedia = async function ( options: Taro.chooseMedia.Option, methodName = chooseMedia.name, ): Promise { @@ -50,7 +52,7 @@ export const chooseMedia = function ( let el = document.getElementById(mediaId) if (!el) { - el = document.createElement(mediaId) + el = document.createElement('input') el.setAttribute('type', 'file') el.setAttribute('id', mediaId) el.setAttribute('style', 'position: fixed; top: -4000px; left: -3000px; z-index: -300;') @@ -63,7 +65,21 @@ export const chooseMedia = function ( } // Note: Input 仅在移动端支持 capture 属性,可以使用 getUserMedia 替代(暂不考虑) - // FIXME sourceType 有多个值时,判断在移动端,提示用户选择【拍摄、从相册选择】 + const md = getMobileDetect() + if (!md.mobile()) { + if (sourceType.length > 1 || sourceType.length < 1) { + try { + const { tapIndex } = await showActionSheet({ + itemList: ['拍摄', '从相册选择'], + }, methodName) + sourceType.splice(0, 1, tapIndex === 0 ? 'camera' : 'album') + } catch (e) { + return handle.fail({ + errMsg: e.errMsg?.replace('^.*:fail ', '') + }) + } + } + } if (sourceType.includes('camera')) { el.setAttribute('capture', camera === 'front' ? 'user' : 'environment') } else { @@ -77,34 +93,34 @@ export const chooseMedia = function ( } else { el.setAttribute('accept', 'image/*, video/*') } - document.body.appendChild(el) - return new Promise((resolve, reject) => { - const TaroMouseEvents = document.createEvent('MouseEvents') - TaroMouseEvents.initEvent('click', true, true) - if (el) { - el.dispatchEvent(TaroMouseEvents) - el.onchange = async function (e) { - const target = e.target as HTMLInputElement - if (target) { - const files = target.files || [] // name webkitRelativePath type - const arr = [...files] - await Promise.all( - arr.map(async item => { - try { - res.tempFiles?.push(await loadMedia(item)) - } catch (error) { - console.error(error) - } - }) - ) - } - handle.success(res, { resolve, reject }) - target.value = '' + if (!el) return + document.body.appendChild(el) + el.onchange = async function (e) { + const target = e.target as HTMLInputElement + if (target) { + const files = target.files || [] + const arr = [...files] + await Promise.all( + arr.map(async item => { + try { + res.tempFiles?.push(await loadMedia(item)) + } catch (error) { + console.error(error) + } + }) + ) } + handle.success(res, { resolve, reject }) + target.value = '' } + el.onabort = () => handle.fail({ errMsg: 'abort' }, { resolve, reject }) + el.oncancel = () => handle.fail({ errMsg: 'cancel' }, { resolve, reject }) + el.onerror = e => handle.fail({ errMsg: e.toString() }, { resolve, reject }) + el.click() }).finally(() => { - el && document.body.removeChild(el) + if (!el) return + document.body.removeChild(el) }) function loadMedia (file: File): Promise { diff --git a/packages/taro-h5/src/api/media/video/chooseVideo.ts b/packages/taro-h5/src/api/media/video/chooseVideo.ts index 8c466f02d0d1..6ee14591d06f 100644 --- a/packages/taro-h5/src/api/media/video/chooseVideo.ts +++ b/packages/taro-h5/src/api/media/video/chooseVideo.ts @@ -36,6 +36,7 @@ export const chooseVideo: typeof Taro.chooseVideo = (options) => { return chooseMedia({ mediaId: 'taroChooseVideo', sourceType, + mediaType: ['video'], maxDuration, camera, success: (res) => { @@ -43,7 +44,9 @@ export const chooseVideo: typeof Taro.chooseVideo = (options) => { success?.(param) complete?.(param) }, - fail, - complete, + fail: (err) => { + fail?.(err) + complete?.(err) + }, }, chooseVideo.name).then(parseRes) } diff --git a/packages/taro-h5/src/api/ui/interaction/index.ts b/packages/taro-h5/src/api/ui/interaction/index.ts index dfff71154062..a42cf3deca7d 100644 --- a/packages/taro-h5/src/api/ui/interaction/index.ts +++ b/packages/taro-h5/src/api/ui/interaction/index.ts @@ -36,7 +36,7 @@ const showToast: typeof Taro.showToast = (options = { title: '' }) => { mask: false }, options) const { success, fail, complete } = options - const handle = new MethodHandler({ name: 'showToast', success, fail, complete }) + const handle = new MethodHandler({ name: showToast.name, success, fail, complete }) if (typeof options.title !== 'string') { return handle.fail({ @@ -72,7 +72,7 @@ const showToast: typeof Taro.showToast = (options = { title: '' }) => { } const hideToast: typeof Taro.hideToast = ({ noConflict = false, success, fail, complete } = {}) => { - const handle = new MethodHandler({ name: 'hideToast', success, fail, complete }) + const handle = new MethodHandler({ name: hideToast.name, success, fail, complete }) if (!toast.el) return handle.success() toast.hide(0, noConflict ? 'toast' : '') return handle.success() @@ -85,7 +85,7 @@ const showLoading: typeof Taro.showLoading = (options = { title: '' }) => { mask: false }, options) const { success, fail, complete } = options - const handle = new MethodHandler({ name: 'showLoading', success, fail, complete }) + const handle = new MethodHandler({ name: showLoading.name, success, fail, complete }) const config = { icon: 'loading', @@ -117,7 +117,7 @@ const showLoading: typeof Taro.showLoading = (options = { title: '' }) => { } const hideLoading: typeof Taro.hideLoading = ({ noConflict = false, success, fail, complete } = {}) => { - const handle = new MethodHandler({ name: 'hideLoading', success, fail, complete }) + const handle = new MethodHandler({ name: hideLoading.name, success, fail, complete }) if (!toast.el) return handle.success() toast.hide(0, noConflict ? 'loading' : '') return handle.success() @@ -135,7 +135,7 @@ const showModal: typeof Taro.showModal = async (options = {}) => { confirmColor: '#3CC51F' }, options) const { success, fail, complete } = options - const handle = new MethodHandler({ name: 'showModal', success, fail, complete }) + const handle = new MethodHandler({ name: showModal.name, success, fail, complete }) if (typeof options.title !== 'string') { return handle.fail({ @@ -227,14 +227,17 @@ function hideModal () { modal.hide() } -const showActionSheet: typeof Taro.showActionSheet = async (options = { itemList: [] }) => { +const showActionSheet = async ( + options: Taro.showActionSheet.Option = { itemList: [] }, + methodName = showActionSheet.name +): Promise => { init(document) options = Object.assign({ itemColor: '#000000', itemList: [] }, options) const { success, fail, complete } = options - const handle = new MethodHandler({ name: 'showActionSheet', success, fail, complete }) + const handle = new MethodHandler({ name: methodName, success, fail, complete }) // list item String if (!Array.isArray(options.itemList)) { From cb617f3cee2b53fc8b1004bd9cc82b9c26f2f5e6 Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Tue, 16 May 2023 17:18:33 +0800 Subject: [PATCH 5/9] =?UTF-8?q?feat(types):=20=E8=A1=A5=E5=85=85=20api=20?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=BA=A6=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/taro/types/api/media/image.d.ts | 13 ++++++++----- packages/taro/types/api/media/video.d.ts | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/taro/types/api/media/image.d.ts b/packages/taro/types/api/media/image.d.ts index 0ff90e160e06..864d2bc70193 100644 --- a/packages/taro/types/api/media/image.d.ts +++ b/packages/taro/types/api/media/image.d.ts @@ -129,14 +129,17 @@ declare module '../../index' { interface Option { /** 最多可以选择的图片张数 * @default 9 + * @supported weapp, alipay, swan, tt, h5, rn */ count?: number /** 所选的图片的尺寸 * @default ['original', 'compressed'] + * @supported weapp, alipay, swan, tt, rn */ sizeType?: Array /** 选择图片的来源 * @default ['album', 'camera'] + * @supported weapp, alipay, swan, tt, h5, rn */ sourceType?: Array /** 接口调用结束的回调函数(调用成功、失败都会执行) */ @@ -309,7 +312,7 @@ declare module '../../index' { interface TaroStatic { /** 保存图片到系统相册。需要[用户授权](https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/authorize.html) scope.writePhotosAlbum - * @supported weapp, rn, alipay, swan, tt + * @supported weapp, alipay, swan, tt, rn * @example * ```tsx * Taro.saveImageToPhotosAlbum({ @@ -333,7 +336,7 @@ declare module '../../index' { previewMedia(option: previewMedia.Option): Promise /** 在新页面中全屏预览图片。预览的过程中用户可以进行保存图片、发送给朋友等操作。 - * @supported weapp, h5, rn, alipay, swan, tt + * @supported weapp, alipay, swan, tt, h5, rn * @example * ```tsx * Taro.previewImage({ @@ -346,7 +349,7 @@ declare module '../../index' { previewImage(option: previewImage.Option): Promise /** 获取图片信息。网络图片需先配置download域名才能生效。 - * @supported weapp, h5, rn, alipay, swan, tt + * @supported weapp, alipay, swan, tt, h5, rn * @example * ```tsx * Taro.getImageInfo({ @@ -385,7 +388,7 @@ declare module '../../index' { editImage(option: editImage.Option): Promise /** 压缩图片接口,可选压缩质量 - * @supported weapp, rn, tt + * @supported weapp, tt, rn * @example * ```tsx * Taro.compressImage({ @@ -416,7 +419,7 @@ declare module '../../index' { /** * 从本地相册选择图片或使用相机拍照。 - * @supported weapp, h5, rn, alipay, swan, tt + * @supported weapp, alipay, swan, tt, h5, rn * @example * ```tsx * Taro.chooseImage({ diff --git a/packages/taro/types/api/media/video.d.ts b/packages/taro/types/api/media/video.d.ts index ddcf1f7f81c1..ad99cccbb399 100644 --- a/packages/taro/types/api/media/video.d.ts +++ b/packages/taro/types/api/media/video.d.ts @@ -235,18 +235,22 @@ declare module '../../index' { interface Option { /** 默认拉起的是前置或者后置摄像头。部分 Android 手机下由于系统 ROM 不支持无法生效 * @default "back" + * @supported weapp, h5 */ camera?: keyof Camera /** 是否压缩所选择的视频文件 * @default true + * @supported weapp */ compressed?: boolean /** 拍摄视频最长拍摄时间,单位秒 * @default 60 + * @supported weapp */ maxDuration?: number /** 视频选择的来源 * @default ['album', 'camera'] + * @supported weapp, h5 */ sourceType?: Array /** 接口调用结束的回调函数(调用成功、失败都会执行) */ @@ -288,26 +292,32 @@ declare module '../../index' { interface Option { /** 最多可以选择的文件个数 * @default 9 + * @supported weapp, h5 */ count?: number /** 文件类型 * @default ['image', 'video'] + * @supported weapp, h5 */ mediaType?: Array /** 图片和视频选择的来源 * @default ['album', 'camera'] + * @supported weapp, h5 */ sourceType?: Array /** 拍摄视频最长拍摄时间,单位秒。时间范围为 3s 至 60s 之间 * @default 10 + * @supported weapp */ maxDuration?: number /** 是否压缩所选文件 * @default ['original', 'compressed'] + * @supported weapp */ sizeType?: Array<'original' | 'compressed'> /** 仅在 sourceType 为 camera 时生效,使用前置或后置摄像头 * @default "back" + * @supported weapp, h5 */ camera?: string /** 接口调用结束的回调函数(调用成功、失败都会执行) */ @@ -478,7 +488,7 @@ declare module '../../index' { compressVideo(option: compressVideo.Option): Promise /** 拍摄视频或从手机相册中选视频。 - * @supported weapp, rn + * @supported weapp, h5, rn * @example * ```tsx * Taro.chooseVideo({ @@ -495,7 +505,7 @@ declare module '../../index' { chooseVideo(option: chooseVideo.Option): Promise /** 拍摄或从手机相册中选择图片或视频。 - * @supported weapp + * @supported weapp, h5 * @example * ```tsx * Taro.chooseMedia({ From f63eaf978bc8a206a85f1a6aa1fa42ada44e7fae Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Tue, 16 May 2023 20:38:59 +0800 Subject: [PATCH 6/9] =?UTF-8?q?fix(h5):=20=E4=BF=AE=E5=A4=8D=20media=20?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E5=B9=B3=E5=8F=B0=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/image/image.tsx | 5 +++- packages/taro-h5/src/api/device/calendar.ts | 6 ++-- packages/taro-h5/src/api/media/image/index.ts | 10 ++++--- .../src/api/media/video/chooseMedia.ts | 30 +++++++++++-------- packages/taro-h5/src/api/media/video/index.ts | 2 +- .../src/api/wxml/IntersectionObserver.ts | 9 ++++-- .../src/api/wxml/MediaQueryObserver.ts | 2 +- packages/taro-h5/src/utils/constants.ts | 2 -- 8 files changed, 40 insertions(+), 26 deletions(-) delete mode 100644 packages/taro-h5/src/utils/constants.ts diff --git a/packages/taro-components/src/components/image/image.tsx b/packages/taro-components/src/components/image/image.tsx index 953424b75dd1..f7ff0dd325d7 100644 --- a/packages/taro-components/src/components/image/image.tsx +++ b/packages/taro-components/src/components/image/image.tsx @@ -1,7 +1,10 @@ import { Component, Prop, h, ComponentInterface, Host, State, Event, EventEmitter } from '@stencil/core' import classNames from 'classnames' -import('intersection-observer') +import( + /* webpackMode: "weak" */ + 'intersection-observer' +) export type Mode = 'scaleToFill' diff --git a/packages/taro-h5/src/api/device/calendar.ts b/packages/taro-h5/src/api/device/calendar.ts index 74d119b4617b..a1114a6b3de8 100644 --- a/packages/taro-h5/src/api/device/calendar.ts +++ b/packages/taro-h5/src/api/device/calendar.ts @@ -1,5 +1,7 @@ +import Taro from '@tarojs/api' + import { temporarilyNotSupport } from '../../utils' // 日历 -export const addPhoneRepeatCalendar = temporarilyNotSupport('addPhoneRepeatCalendar') -export const addPhoneCalendar = temporarilyNotSupport('addPhoneCalendar') +export const addPhoneRepeatCalendar: typeof Taro.addPhoneRepeatCalendar = temporarilyNotSupport('addPhoneRepeatCalendar') +export const addPhoneCalendar: typeof Taro.addPhoneCalendar = temporarilyNotSupport('addPhoneCalendar') diff --git a/packages/taro-h5/src/api/media/image/index.ts b/packages/taro-h5/src/api/media/image/index.ts index 3cbcd34a4efd..f434266c35ea 100644 --- a/packages/taro-h5/src/api/media/image/index.ts +++ b/packages/taro-h5/src/api/media/image/index.ts @@ -1,14 +1,16 @@ -import { temporarilyNotSupport } from '../../../utils' +import Taro from '@tarojs/api' + +import { permanentlyNotSupport, temporarilyNotSupport } from '../../../utils' // 图片 -export const saveImageToPhotosAlbum = temporarilyNotSupport('saveImageToPhotosAlbum') -export const previewMedia = temporarilyNotSupport('previewMedia') +export const saveImageToPhotosAlbum: typeof Taro.saveImageToPhotosAlbum = temporarilyNotSupport('saveImageToPhotosAlbum') +export const previewMedia: typeof Taro.saveImageToPhotosAlbum = temporarilyNotSupport('previewMedia') export * from './getImageInfo' export * from './previewImage' export const compressImage = temporarilyNotSupport('compressImage') -export const chooseMessageFile = temporarilyNotSupport('chooseMessageFile') +export const chooseMessageFile = permanentlyNotSupport('chooseMessageFile') export * from './chooseImage' diff --git a/packages/taro-h5/src/api/media/video/chooseMedia.ts b/packages/taro-h5/src/api/media/video/chooseMedia.ts index d6022c6eb496..574cecfab4b3 100644 --- a/packages/taro-h5/src/api/media/video/chooseMedia.ts +++ b/packages/taro-h5/src/api/media/video/chooseMedia.ts @@ -3,7 +3,6 @@ import { getMobileDetect } from '@tarojs/router/dist/utils/navigate' import { showActionSheet } from '../../../api/ui' import { getParameterError, shouldBeObject } from '../../../utils' -import { REG_MEDIA } from '../../../utils/constants' import { MethodHandler } from '../../../utils/handler' /** @@ -66,7 +65,7 @@ export const chooseMedia = async function ( // Note: Input 仅在移动端支持 capture 属性,可以使用 getUserMedia 替代(暂不考虑) const md = getMobileDetect() - if (!md.mobile()) { + if (md.mobile()) { if (sourceType.length > 1 || sourceType.length < 1) { try { const { tapIndex } = await showActionSheet({ @@ -136,25 +135,32 @@ export const chooseMedia = async function ( originalFileObj: file } - if (REG_MEDIA.test(res.fileType)) { + if (/^video\//.test(res.fileType)) { // Video - const reader = new FileReader() const video = document.createElement('video') + const reader = new FileReader() + video.crossOrigin = 'Anonymous' video.preload = 'metadata' video.src = res.tempFilePath return new Promise((resolve, reject) => { - reader.onload = function () { - video.onloadedmetadata = async () => { - res.duration = video.duration - res.height = video.videoHeight - res.width = video.videoWidth - res.thumbTempFilePath = getThumbTempFilePath(video, res.height, res.width, 0.8) - resolve(res) - } + // 对齐旧版本实现 + reader.onload = (event) => { + res.tempFilePath = event.target?.result as string } reader.onerror = e => reject(e) reader.readAsDataURL(res.originalFileObj) + + video.onloadedmetadata = () => { + res.duration = video.duration + res.height = video.videoHeight + res.width = video.videoWidth + } + video.oncanplay = () => { + res.thumbTempFilePath = getThumbTempFilePath(video, res.height, res.width, 0.8) + resolve(res) + } + video.onerror = e => reject(e) }) } else { // Image diff --git a/packages/taro-h5/src/api/media/video/index.ts b/packages/taro-h5/src/api/media/video/index.ts index f3b590136790..2a73744cb665 100644 --- a/packages/taro-h5/src/api/media/video/index.ts +++ b/packages/taro-h5/src/api/media/video/index.ts @@ -3,7 +3,7 @@ import Taro from '@tarojs/api' import { findDOM, temporarilyNotSupport } from '../../../utils' // 视频 -export const saveVideoToPhotosAlbum = temporarilyNotSupport('saveVideoToPhotosAlbum') +export const saveVideoToPhotosAlbum: typeof Taro.saveVideoToPhotosAlbum = temporarilyNotSupport('saveVideoToPhotosAlbum') export const openVideoEditor = temporarilyNotSupport('openVideoEditor') export const getVideoInfo = temporarilyNotSupport('getVideoInfo') diff --git a/packages/taro-h5/src/api/wxml/IntersectionObserver.ts b/packages/taro-h5/src/api/wxml/IntersectionObserver.ts index 7a9c6982111f..cefb48a81b4d 100644 --- a/packages/taro-h5/src/api/wxml/IntersectionObserver.ts +++ b/packages/taro-h5/src/api/wxml/IntersectionObserver.ts @@ -1,8 +1,11 @@ -import Taro from '@tarojs/taro' +import Taro from '@tarojs/api' import { findDOM } from '../../utils' -// pollify -import('intersection-observer') + +import( + /* webpackMode: "weak" */ + 'intersection-observer' +) type TElement = Document | HTMLElement | Element diff --git a/packages/taro-h5/src/api/wxml/MediaQueryObserver.ts b/packages/taro-h5/src/api/wxml/MediaQueryObserver.ts index 8fbe8fc4872b..3a18986a1361 100644 --- a/packages/taro-h5/src/api/wxml/MediaQueryObserver.ts +++ b/packages/taro-h5/src/api/wxml/MediaQueryObserver.ts @@ -1,6 +1,6 @@ +import Taro from '@tarojs/api' import { isFunction, toKebabCase } from '@tarojs/shared' -import Taro from '@tarojs/taro' function generateMediaQueryStr (descriptor: Taro.MediaQueryObserver.descriptor) { const mediaQueryArr: string[] = [] diff --git a/packages/taro-h5/src/utils/constants.ts b/packages/taro-h5/src/utils/constants.ts deleted file mode 100644 index d81db150fac0..000000000000 --- a/packages/taro-h5/src/utils/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const REG_MEDIA = /\.(mp4|webm|ogg|mp3|m4a|wav|flac|aac)(\?.*)?$/ -export const REG_IMAGE = /\.(png|jpe?g|gif|bpm|svg|webp)(\?.*)?$/ From 7b613d468eb25c188b02e64437f808df00cbd90f Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Tue, 16 May 2023 21:32:34 +0800 Subject: [PATCH 7/9] feat(h5): support get video info --- .../src/api/media/video/getVideoInfo.ts | 68 +++++++++++++++++++ packages/taro-h5/src/api/media/video/index.ts | 3 +- 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 packages/taro-h5/src/api/media/video/getVideoInfo.ts diff --git a/packages/taro-h5/src/api/media/video/getVideoInfo.ts b/packages/taro-h5/src/api/media/video/getVideoInfo.ts new file mode 100644 index 000000000000..8745ba870b06 --- /dev/null +++ b/packages/taro-h5/src/api/media/video/getVideoInfo.ts @@ -0,0 +1,68 @@ +import Taro from '@tarojs/api' + +import { getParameterError, shouldBeObject } from '../../../utils' +import { MethodHandler } from '../../../utils/handler' + +export const getVideoInfo: typeof Taro.getVideoInfo = async function (options) { + // options must be an Object + const isObject = shouldBeObject(options) + if (!isObject.flag) { + const res = { errMsg: `${getVideoInfo.name}:fail ${isObject.msg}` } + console.error(res.errMsg) + return Promise.reject(res) + } + const res: Partial = { + orientation: 'up', + type: '', + duration: 0, + size: 0, + height: 0, + width: 0, + fps: 30, + bitrate: 0, + } + const { + src, + success, + fail, + complete, + } = options + const handle = new MethodHandler({ name: getVideoInfo.name, success, fail, complete }) + + if (typeof src !== 'string') { + res.errMsg = getParameterError({ + para: 'src', + correct: 'String', + wrong: src + }) + return handle.fail(res) + } + + const video = document.createElement('video') + video.crossOrigin = 'Anonymous' + video.preload = 'metadata' + video.src = src + + return new Promise((resolve, reject) => { + video.onloadedmetadata = () => { + res.duration = video.duration + res.height = video.videoHeight + res.width = video.videoWidth + + fetch(src) + .then(async e => { + const blob = await e.blob() + res.type = blob.type + res.size = blob.size + res.bitrate = blob.size / video.duration + + handle.success(res, { resolve, reject }) + }) + .catch(e => { + handle.fail({ + errMsg: e.toString() + }, { resolve, reject }) + }) + } + }) +} diff --git a/packages/taro-h5/src/api/media/video/index.ts b/packages/taro-h5/src/api/media/video/index.ts index 2a73744cb665..b820721ca58c 100644 --- a/packages/taro-h5/src/api/media/video/index.ts +++ b/packages/taro-h5/src/api/media/video/index.ts @@ -5,7 +5,8 @@ import { findDOM, temporarilyNotSupport } from '../../../utils' // 视频 export const saveVideoToPhotosAlbum: typeof Taro.saveVideoToPhotosAlbum = temporarilyNotSupport('saveVideoToPhotosAlbum') export const openVideoEditor = temporarilyNotSupport('openVideoEditor') -export const getVideoInfo = temporarilyNotSupport('getVideoInfo') + +export * from './getVideoInfo' /** * 创建 video 上下文 VideoContext 对象。 From 1efca7cada2c2c2a132d6e3807bbc9e217d253f4 Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Wed, 17 May 2023 13:39:43 +0800 Subject: [PATCH 8/9] fix(h5): add whatwg-fetch import --- packages/taro-h5/src/api/media/video/getVideoInfo.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/taro-h5/src/api/media/video/getVideoInfo.ts b/packages/taro-h5/src/api/media/video/getVideoInfo.ts index 8745ba870b06..4d4ae05cb7ed 100644 --- a/packages/taro-h5/src/api/media/video/getVideoInfo.ts +++ b/packages/taro-h5/src/api/media/video/getVideoInfo.ts @@ -1,3 +1,5 @@ +import 'whatwg-fetch' + import Taro from '@tarojs/api' import { getParameterError, shouldBeObject } from '../../../utils' From 05a5207802600ddc1147b9223f4bdc59e623db52 Mon Sep 17 00:00:00 2001 From: ZakaryCode Date: Thu, 18 May 2023 11:15:40 +0800 Subject: [PATCH 9/9] fix(h5): trans webpackMode weak 2 lazy --- .../taro-components/src/components/image/image.tsx | 5 +---- .../taro-components/src/components/video/video.tsx | 2 +- packages/taro-h5/src/api/media/image/chooseImage.ts | 6 +++--- packages/taro-h5/src/api/media/video/chooseMedia.ts | 2 +- packages/taro-h5/src/api/media/video/chooseVideo.ts | 4 ++-- packages/taro-h5/src/api/media/video/getVideoInfo.ts | 8 ++++---- packages/taro-h5/src/api/ui/interaction/index.ts | 12 ++++++------ .../taro-h5/src/api/wxml/IntersectionObserver.ts | 5 +---- 8 files changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/taro-components/src/components/image/image.tsx b/packages/taro-components/src/components/image/image.tsx index f7ff0dd325d7..953424b75dd1 100644 --- a/packages/taro-components/src/components/image/image.tsx +++ b/packages/taro-components/src/components/image/image.tsx @@ -1,10 +1,7 @@ import { Component, Prop, h, ComponentInterface, Host, State, Event, EventEmitter } from '@stencil/core' import classNames from 'classnames' -import( - /* webpackMode: "weak" */ - 'intersection-observer' -) +import('intersection-observer') export type Mode = 'scaleToFill' diff --git a/packages/taro-components/src/components/video/video.tsx b/packages/taro-components/src/components/video/video.tsx index a28271e9b1be..f1d9699e7507 100644 --- a/packages/taro-components/src/components/video/video.tsx +++ b/packages/taro-components/src/components/video/video.tsx @@ -335,7 +335,7 @@ export class Video implements ComponentInterface { if (isHls(src)) { import( - /* webpackMode: "weak" */ + /* webpackExports: ["default"] */ 'hls.js' ).then(e => { const Hls = e.default diff --git a/packages/taro-h5/src/api/media/image/chooseImage.ts b/packages/taro-h5/src/api/media/image/chooseImage.ts index 78c1e9cb6dcc..ac5f686bc0d1 100644 --- a/packages/taro-h5/src/api/media/image/chooseImage.ts +++ b/packages/taro-h5/src/api/media/image/chooseImage.ts @@ -1,7 +1,7 @@ import Taro from '@tarojs/api' import { shouldBeObject } from '../../../utils' -import { chooseMedia } from '../video' +import { chooseMedia } from '../video/chooseMedia' /** * 从本地相册选择图片或使用相机拍照。 @@ -11,7 +11,7 @@ export const chooseImage: typeof Taro.chooseImage = function (options) { // options must be an Object const isObject = shouldBeObject(options) if (!isObject.flag) { - const res = { errMsg: `${chooseImage.name}:fail ${isObject.msg}` } + const res = { errMsg: `chooseImage:fail ${isObject.msg}` } console.error(res.errMsg) return Promise.reject(res) } @@ -57,5 +57,5 @@ export const chooseImage: typeof Taro.chooseImage = function (options) { fail?.(err) complete?.(err) }, - }, chooseImage.name).then(parseRes) + }, 'chooseImage').then(parseRes) } diff --git a/packages/taro-h5/src/api/media/video/chooseMedia.ts b/packages/taro-h5/src/api/media/video/chooseMedia.ts index 574cecfab4b3..21d16c440b4b 100644 --- a/packages/taro-h5/src/api/media/video/chooseMedia.ts +++ b/packages/taro-h5/src/api/media/video/chooseMedia.ts @@ -10,7 +10,7 @@ import { MethodHandler } from '../../../utils/handler' */ export const chooseMedia = async function ( options: Taro.chooseMedia.Option, - methodName = chooseMedia.name, + methodName = 'chooseMedia', ): Promise { // options must be an Object const isObject = shouldBeObject(options) diff --git a/packages/taro-h5/src/api/media/video/chooseVideo.ts b/packages/taro-h5/src/api/media/video/chooseVideo.ts index 6ee14591d06f..d9670964288d 100644 --- a/packages/taro-h5/src/api/media/video/chooseVideo.ts +++ b/packages/taro-h5/src/api/media/video/chooseVideo.ts @@ -11,7 +11,7 @@ export const chooseVideo: typeof Taro.chooseVideo = (options) => { // options must be an Object const isObject = shouldBeObject(options) if (!isObject.flag) { - const res = { errMsg: `${chooseVideo.name}:fail ${isObject.msg}` } + const res = { errMsg: `chooseVideo:fail ${isObject.msg}` } console.error(res.errMsg) return Promise.reject(res) } @@ -48,5 +48,5 @@ export const chooseVideo: typeof Taro.chooseVideo = (options) => { fail?.(err) complete?.(err) }, - }, chooseVideo.name).then(parseRes) + }, 'chooseVideo').then(parseRes) } diff --git a/packages/taro-h5/src/api/media/video/getVideoInfo.ts b/packages/taro-h5/src/api/media/video/getVideoInfo.ts index 4d4ae05cb7ed..fcced6db65a7 100644 --- a/packages/taro-h5/src/api/media/video/getVideoInfo.ts +++ b/packages/taro-h5/src/api/media/video/getVideoInfo.ts @@ -9,7 +9,7 @@ export const getVideoInfo: typeof Taro.getVideoInfo = async function (options) { // options must be an Object const isObject = shouldBeObject(options) if (!isObject.flag) { - const res = { errMsg: `${getVideoInfo.name}:fail ${isObject.msg}` } + const res = { errMsg: `getVideoInfo:fail ${isObject.msg}` } console.error(res.errMsg) return Promise.reject(res) } @@ -29,7 +29,7 @@ export const getVideoInfo: typeof Taro.getVideoInfo = async function (options) { fail, complete, } = options - const handle = new MethodHandler({ name: getVideoInfo.name, success, fail, complete }) + const handle = new MethodHandler({ name: 'getVideoInfo', success, fail, complete }) if (typeof src !== 'string') { res.errMsg = getParameterError({ @@ -50,14 +50,14 @@ export const getVideoInfo: typeof Taro.getVideoInfo = async function (options) { res.duration = video.duration res.height = video.videoHeight res.width = video.videoWidth - + fetch(src) .then(async e => { const blob = await e.blob() res.type = blob.type res.size = blob.size res.bitrate = blob.size / video.duration - + handle.success(res, { resolve, reject }) }) .catch(e => { diff --git a/packages/taro-h5/src/api/ui/interaction/index.ts b/packages/taro-h5/src/api/ui/interaction/index.ts index a42cf3deca7d..4369addedd39 100644 --- a/packages/taro-h5/src/api/ui/interaction/index.ts +++ b/packages/taro-h5/src/api/ui/interaction/index.ts @@ -36,7 +36,7 @@ const showToast: typeof Taro.showToast = (options = { title: '' }) => { mask: false }, options) const { success, fail, complete } = options - const handle = new MethodHandler({ name: showToast.name, success, fail, complete }) + const handle = new MethodHandler({ name: 'showToast', success, fail, complete }) if (typeof options.title !== 'string') { return handle.fail({ @@ -72,7 +72,7 @@ const showToast: typeof Taro.showToast = (options = { title: '' }) => { } const hideToast: typeof Taro.hideToast = ({ noConflict = false, success, fail, complete } = {}) => { - const handle = new MethodHandler({ name: hideToast.name, success, fail, complete }) + const handle = new MethodHandler({ name: 'hideToast', success, fail, complete }) if (!toast.el) return handle.success() toast.hide(0, noConflict ? 'toast' : '') return handle.success() @@ -85,7 +85,7 @@ const showLoading: typeof Taro.showLoading = (options = { title: '' }) => { mask: false }, options) const { success, fail, complete } = options - const handle = new MethodHandler({ name: showLoading.name, success, fail, complete }) + const handle = new MethodHandler({ name: 'showLoading', success, fail, complete }) const config = { icon: 'loading', @@ -117,7 +117,7 @@ const showLoading: typeof Taro.showLoading = (options = { title: '' }) => { } const hideLoading: typeof Taro.hideLoading = ({ noConflict = false, success, fail, complete } = {}) => { - const handle = new MethodHandler({ name: hideLoading.name, success, fail, complete }) + const handle = new MethodHandler({ name: 'hideLoading', success, fail, complete }) if (!toast.el) return handle.success() toast.hide(0, noConflict ? 'loading' : '') return handle.success() @@ -135,7 +135,7 @@ const showModal: typeof Taro.showModal = async (options = {}) => { confirmColor: '#3CC51F' }, options) const { success, fail, complete } = options - const handle = new MethodHandler({ name: showModal.name, success, fail, complete }) + const handle = new MethodHandler({ name: 'showModal', success, fail, complete }) if (typeof options.title !== 'string') { return handle.fail({ @@ -229,7 +229,7 @@ function hideModal () { const showActionSheet = async ( options: Taro.showActionSheet.Option = { itemList: [] }, - methodName = showActionSheet.name + methodName = 'showActionSheet' ): Promise => { init(document) options = Object.assign({ diff --git a/packages/taro-h5/src/api/wxml/IntersectionObserver.ts b/packages/taro-h5/src/api/wxml/IntersectionObserver.ts index cefb48a81b4d..569af78b8bdc 100644 --- a/packages/taro-h5/src/api/wxml/IntersectionObserver.ts +++ b/packages/taro-h5/src/api/wxml/IntersectionObserver.ts @@ -2,10 +2,7 @@ import Taro from '@tarojs/api' import { findDOM } from '../../utils' -import( - /* webpackMode: "weak" */ - 'intersection-observer' -) +import('intersection-observer') type TElement = Document | HTMLElement | Element