fix:所有document访问前加typeof守卫,非H5自动fallback系统相机

This commit is contained in:
97694732@qq.com 2026-06-06 17:21:15 +08:00
parent 1ee3a0a274
commit e6decbb433

View File

@ -1,12 +1,12 @@
<template> <template>
<view class="cc-page"> <view class="cc-page">
<!-- 摄像头预览区WebRTC --> <!-- 摄像头预览区 -->
<view class="cc-camera-wrap"> <view class="cc-camera-wrap">
<video id="ccVideo" class="cc-video" autoplay playsinline muted></video> <video id="ccVideo" ref="ccVideo" class="cc-video" autoplay playsinline muted v-if="useWebRTC"></video>
<canvas id="ccCanvas" class="cc-canvas" style="display:none;"></canvas> <view class="cc-camera-hint" v-if="!useWebRTC">
<view class="cc-camera-hint" v-if="!ctxReady"> <text class="cc-hint-text">点击拍照按钮调用系统相机</text>
<text class="cc-hint-text">{{ hintText }}</text>
</view> </view>
<canvas id="ccCanvas" ref="ccCanvas" class="cc-canvas" style="display:none;"></canvas>
</view> </view>
<!-- 已拍照九宫格 --> <!-- 已拍照九宫格 -->
@ -43,24 +43,43 @@
capturedList: [], capturedList: [],
mediaStream: null, mediaStream: null,
ctxReady: false, ctxReady: false,
hintText: '摄像头启动中...' useWebRTC: false
} }
}, },
onReady() { onReady() {
this.startCamera() this.checkEnvironment()
}, },
onUnload() { onUnload() {
this.stopCamera() this.stopCamera()
}, },
methods: { methods: {
startCamera() { //
var that = this checkEnvironment() {
this.hintText = '摄像头启动中...' // H5 document getUserMedia
try { try {
setTimeout(function() { if (typeof document !== 'undefined' && typeof navigator !== 'undefined' && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
this.useWebRTC = true
this.startWebRTC()
} else {
this.useWebRTC = false
this.ctxReady = true
}
} catch (e) {
this.useWebRTC = false
this.ctxReady = true
}
},
// WebRTC H5
startWebRTC() {
var that = this
try {
if (typeof document === 'undefined') {
this.ctxReady = true
return
}
var video = document.getElementById('ccVideo') var video = document.getElementById('ccVideo')
if (!video) { if (!video) {
that.hintText = '视频组件加载失败' this.ctxReady = true
return return
} }
navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment', width: 1280, height: 720 } }) navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment', width: 1280, height: 720 } })
@ -69,17 +88,15 @@
video.srcObject = stream video.srcObject = stream
video.play() video.play()
that.ctxReady = true that.ctxReady = true
that.hintText = '' console.log('WebRTC摄像头已就绪')
console.log('摄像头已就绪(WebRTC)')
}) })
.catch(function(err) { .catch(function(err) {
console.error('getUserMedia失败:', err) console.error('getUserMedia失败:', err)
that.hintText = '摄像头访问被拒绝: ' + (err.message || '') that.ctxReady = true
}) })
}, 500)
} catch (e) { } catch (e) {
console.error('摄像头启动异常:', e) console.error('摄像头启动异常:', e)
this.hintText = '摄像头启动异常' this.ctxReady = true
} }
}, },
stopCamera() { stopCamera() {
@ -96,37 +113,44 @@
uni.showToast({ title: '最多拍9张', icon: 'none' }) uni.showToast({ title: '最多拍9张', icon: 'none' })
return return
} }
// canvas video if (this.useWebRTC && this.mediaStream && this.ctxReady) {
var video = document.getElementById('ccVideo') this.webRTCCapture()
} else {
this.systemCapture()
}
},
// WebRTC
webRTCCapture() {
if (typeof document === 'undefined') {
this.systemCapture()
return
}
var canvas = document.getElementById('ccCanvas') var canvas = document.getElementById('ccCanvas')
if (!video || !canvas) { var video = document.getElementById('ccVideo')
uni.showToast({ title: '拍照失败', icon: 'none' }) if (!canvas || !video) {
this.systemCapture()
return return
} }
canvas.width = video.videoWidth || 1280 canvas.width = video.videoWidth || 1280
canvas.height = video.videoHeight || 720 canvas.height = video.videoHeight || 720
var ctx = canvas.getContext('2d') var ctx = canvas.getContext('2d')
ctx.drawImage(video, 0, 0, canvas.width, canvas.height) ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
// blob
var that = this
canvas.toBlob(function(blob) {
if (!blob) {
// fallback: data url
var dataUrl = canvas.toDataURL('image/jpeg', 0.85) var dataUrl = canvas.toDataURL('image/jpeg', 0.85)
that.capturedList.push(dataUrl) this.capturedList.push(dataUrl)
return },
} //
// FileReader blob dataUrl uni.saveFile systemCapture() {
var reader = new FileReader() var that = this
reader.onloadend = function() { uni.chooseImage({
var base64 = reader.result count: 1,
if (base64) { sourceType: ['camera'],
// base64 data url sizeType: ['original'],
that.capturedList.push(base64) success: function(res) {
if (res.tempFilePaths && res.tempFilePaths.length > 0) {
that.capturedList.push(res.tempFilePaths[0])
} }
} }
reader.readAsDataURL(blob) })
}, 'image/jpeg', 0.85)
}, },
deletePhoto(idx) { deletePhoto(idx) {
this.capturedList.splice(idx, 1) this.capturedList.splice(idx, 1)
@ -136,7 +160,6 @@
uni.showToast({ title: '请先拍照', icon: 'none' }) uni.showToast({ title: '请先拍照', icon: 'none' })
return return
} }
//
this.stopCamera() this.stopCamera()
var pages = getCurrentPages() var pages = getCurrentPages()
var prevPage = pages[pages.length - 2] var prevPage = pages[pages.length - 2]
@ -162,6 +185,9 @@
position: relative; position: relative;
overflow: hidden; overflow: hidden;
background: #111; background: #111;
display: flex;
align-items: center;
justify-content: center;
} }
.cc-video { .cc-video {
width: 100%; width: 100%;
@ -172,21 +198,12 @@
display: none; display: none;
} }
.cc-camera-hint { .cc-camera-hint {
position: absolute; text-align: center;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background: #111;
padding: 40rpx; padding: 40rpx;
} }
.cc-hint-text { .cc-hint-text {
color: #999; color: #999;
font-size: 28rpx; font-size: 28rpx;
text-align: center;
} }
.cc-thumb-bar { .cc-thumb-bar {
background: #1a1a1a; background: #1a1a1a;