h5页面调用手机拍照 出现刷新或闪退
问题原因
根据产品业务,需要在h5页面调用手机的拍照,出现了页面刷新或闪退:
- 这是微信内置浏览器内存不足导致的,安卓手机此问题常见,尤其是红米低端机出现概率更高(自己就是用的红米手机);
- vant官网在van-uploader组件介绍页面的最下面也说了有这个问题;
- 使用input标签,调用拍照也是一样的页面刷新或闪退
- 是安卓自身的原因:链接 参考文章.
解决办法(使用van-uploader组件)
- van-uploader的标签加capture=“camera”,并限制格式result-type=“file”:
<van-uploader
ref="uploaderRef"
:before-read="handleBeforeRead"
result-type="file"
v-model="fileList"
capture="camera"
:afterRead="handleAfterRead"
max-count="1"
/>
- 在handleBeforeRead方法时,对拍照图片进行压缩:
import Compressor from 'compressorjs'
// An highlighted block
return new Promise((resolve, reject) => {
new Compressor(file, {
//压缩质量, 0-1
quality: 0.6,
//转换的类型,默认为 image/png
convertTypes: ['image/jpeg'],
//需要压缩的起始大小,默认5M, 5 * 1000 * 1000
convertSize: 5000000,
//压缩成功后处理
success(result) {
resolve(result);
},
error(err) {
console.log(err.message);
proxy.$toast({ type: 'fail', message: err.message })
reject()
},
});
});
- 在handleAfterRead方法时,返回的file是一个对象,并不是后端需要file文件流,需要file.file传给后端,且file.file可能不存在name,需要注意一下。
自己封装的组件
1.组件取名:Vue3Camera.vue (privateUpload是自定义的请求接口,也就是上传图片的接口)
<template>
<van-uploader
ref="uploaderRef"
:before-read="handleBeforeRead"
v-model="fileList"
capture="camera"
result-type="file"
:afterRead="handleAfterRead"
max-count="1"
class="upload-fixed"
/>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: 'Vue3Camera'
})
</script>
<script lang="ts" setup>
import { getCurrentInstance, ref,reactive } from "vue";
import Compressor from "compressorjs";
import { privateUpload } from "@/api/common";
import { v4 as uuidV4 } from 'uuid'
import { Toast, UploaderInstance } from "vant";
const { proxy }: any = getCurrentInstance()
const emits = defineEmits(['uploadSuccess'])
const state = reactive({
groupId:''
})
const uploaderRef = ref<UploaderInstance>();
let fileList = ref<any[]>([])
const handleBeforeRead:any = (file:any) =>{
return new Promise((resolve, reject) => {
new Compressor(file, {
//压缩质量, 0-1
quality: 0.6,
//转换的类型,默认为 image/png
convertTypes: ['image/jpeg'],
//需要压缩的起始大小,默认5M, 5 * 1000 * 1000
convertSize: 5000000,
//压缩成功后处理
success(result) {
resolve(result);
},
error(err) {
console.log(err.message);
proxy.$toast({ type: 'fail', message: err.message })
reject()
},
});
});
}
const handleAfterRead = (file:any)=>{
console.log('file',file)
if(file.file){
handleUploadFile(file.file)
}else{
proxy.$toast({ type: 'fail', message: '拍照失败' })
}
}
const handleChooseFile = ()=>{
uploaderRef.value?.chooseFile();
}
const handleUploadFile = (file: any) => {
let fileExtensionArray = file.name.split('.')
let fileExtension = fileExtensionArray[fileExtensionArray.length - 1]
let data = ''
let tempFile = reactive({
uuid: '',
name: file.name,
url: data,
isImage: true,
status: 'uploading',
message: '上传中...',
})
state.groupId = uuidV4().replace(/-/g, '')
fileList.value.push(tempFile)
let reqData = new FormData()
reqData.append('files', file)
reqData.append('groupId', state.groupId)
privateUpload(reqData)
.then((res: any) => {
// proxy.$toast({ type: 'success', message: '操作成功' })
if (res.code === '0') {
emits('uploadSuccess', state.groupId)
} else {
Toast({ type: 'fail', message: res.message })
}
})
.catch((err) => {
tempFile.status = 'failed'
tempFile.message = '上传失败'
})
}
defineExpose({
handleChooseFile
})
</script>
<style lang="css" scoped>
.upload-fixed {
position: absolute;
right: 100px;
top: 100px;
display: none;
}
</style>
2.调用
<Vue3Camera @upload-success="handleUploadSuccess" ref="vue3CameraRef" :key="refreshKey"></Vue3Camera>
const vue3CameraRef = ref<any>()
//调用相机
vue3CameraRef.value.handleChooseFile()
//拍照上传成功
const refreshKey = ref(0)
const handleUploadSuccess = (groupId: any) => {
refreshKey.value++
console.log('签到拍照上传成功', groupId)
//groupId 是上传图片后,后端保存图片的uuid
//成功之后,你可以调用签到等接口
}
3.虽然这样处理之后,ios与多数安卓没什么问题了,但是红米低端机还是偶尔有问题,如果是在自己的app里使用,建议app提供调用相机的方法来处理。
完结
本人程序员思考很久后,决定离职,目前已经离职,准备换行业折腾了,再见了大家,再见了csdn!!!!!!!!!!