
简体中文
相机组件
Web | 微信小程序 | Android | iOS | HarmonyOS |
---|---|---|---|---|
x | 4.41 | 4.61 | 4.61 | x |
名称 | 类型 | 默认值 | 兼容性 | 描述 | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
flash | string | - | 闪光灯,值为auto, on, off | ||||||||||||||||
| |||||||||||||||||||
device-position | string | - | 前置或后置,值为front, back | ||||||||||||||||
| |||||||||||||||||||
mode | string | - | (string) 应用模式,只在初始化时有效,不能动态变更 | ||||||||||||||||
| |||||||||||||||||||
resolution | string | - | (string) 分辨率,不支持动态修改 | ||||||||||||||||
| |||||||||||||||||||
frame-size | string | - | (string) 指定期望的相机帧数据尺寸 | ||||||||||||||||
| |||||||||||||||||||
@stop | (event: UniCameraStopEvent) => void | - | 摄像头在非正常终止时触发,如退出后台等情况 | ||||||||||||||||
@error | (event: UniCameraErrorEvent) => void | - | 用户不允许使用摄像头时触发 | ||||||||||||||||
@initdone | (event: UniCameraInitDoneEvent) => void | - | - | ||||||||||||||||
@scancode | eventhandle | - | - |
名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
---|---|---|---|---|---|
errorCause | string | 否 | - | - |
名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
---|---|---|---|---|---|
msg | string | 否 | - | - |
名称 | 类型 | 必填 | 默认值 | 兼容性 | 描述 |
---|---|---|---|---|---|
maxZoom | number | 否 | - | - |
camera组件的操作api为uni.createCameraContext()。
给camera组件设一个id属性,将id的值传入uni.createCameraContext(),即可得到camera组件的上下文对象,进一步可使用.takePhoto()
、.startRecord()
等方法。
该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验
<template>
<view style="flex: 1;">
<camera style="width: 100%; height: 300px;" :resolution="'medium'" :device-position="devicePosition"
:flash="flash" :frame-size="frameSize" @stop="handleStop" @error="handleError" @initdone="handleInitDone">
</camera>
<scroll-view style="flex: 1;">
<view>
<button type="default" @click="switchDevicePosition">切换前后摄像头</button>
<button type="default" @click="switchFlash">闪光灯</button>
<button type="default" @click="setOnFrameListener">设置帧数据监听</button>
<button type="default" @click="startFrameListener">开始捕捉帧数据</button>
<button type="default" @click="stopFrameListener">停止捕捉帧数据</button>
<view>
<view class="uni-title">
<text class="uni-title-text">设置预览缩放</text>
</view>
<view class="uni-camera-wrapper">
<slider class="uni-camera-test-host" :disabled="maxZoom == 0" :show-value="true" :min="1"
:max="maxZoom" :value="1" @change="zoomSliderChange" />
</view>
</view>
<view>
<view class="uni-title">
<text class="uni-title-text">拍摄照片示例</text>
<button type="default" @click="handleTakePhoto">拍摄照片</button>
<radio-group style="flex-direction: row;" name="成像质量" @change="takePhotoQualityChange">
<radio value="normal" :checked="true">普通质量</radio>
<radio value="low">低质量</radio>
<radio value="high">高质量</radio>
<radio value="original">原图</radio>
</radio-group>
</view>
<view class="uni-camera-wrapper">
<image class="uni-camera-test-host-without-flex" style="width: 150px;height: 150px;"
v-if="imageSrc != ''" :src="imageSrc"></image>
</view>
</view>
<view>
<view class="uni-title">
<text class="uni-title-text">录制视频示例</text>
<view style="flex-direction: row;margin-top: 8px;">
<text class="uni-title-size">录制时长:</text>
<input class="uni-title-size"
style="width: 50px; margin-left: 10px;border: 0.5px solid grey;text-align: right;"
type="number" @input="timeoutInput" :value="timeout" />
<text class="uni-title-size" style="margin-left: 8px;">秒</text>
</view>
<button type="default" style="font-family: monospace;margin-top: 8px;" @click="startRecord"
:disabled="startRecordStatus">{{ startRecordStatus ? `${remain}秒` : "录制视频" }}</button>
<button type="default" @click="stopRecord">停止录制</button>
<radio-group style="flex-direction: row;margin-top: 8px;" name="是否压缩"
@change="startRecordCompressChange">
<radio value="0" :checked="true">未启动视频压缩</radio>
<radio value="1">启动视频压缩</radio>
</radio-group>
</view>
<view class="uni-camera-wrapper">
<video class="uni-camera-test-host-without-flex" style="width: 300px;height: 300px;"
v-if="videoSrc != ''" :src="videoSrc" :controls="true"></video>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
devicePosition: "back",
flash: "off",
frameSize: "medium",
listener: null as CameraContextCameraFrameListener | null,
maxZoom: 0,
imageSrc: "",
quality: "normal",
timeout: 30,
compressed: false,
videoSrc: "",
startRecordStatus: false,
remain: 0,
intervalId: -1,
timeoutStr: '30'
}
},
onLoad() {
},
methods: {
switchDevicePosition() {
this.devicePosition = this.devicePosition == "back" ? "front" : "back"
},
switchFlash() {
this.flash = this.flash == "torch" ? "off" : "torch"
},
handleStop(e : UniCameraStopEvent) {
console.log("stop", e.detail);
},
handleError(e : UniCameraErrorEvent) {
console.log("error", e.detail);
},
handleInitDone(e : UniCameraInitDoneEvent) {
console.log("initdone", e.detail);
this.maxZoom = e.detail.maxZoom ?? 0
},
zoomSliderChange(event : UniSliderChangeEvent) {
const value = event.detail.value
const context = uni.createCameraContext();
context?.setZoom({
zoom: value,
success: (e : any) => {
console.log(e);
}
} as CameraContextSetZoomOptions)
},
handleTakePhoto() {
const context = uni.createCameraContext();
context?.takePhoto({
quality: this.quality,
selfieMirror: false,
success: (res : CameraContextTakePhotoResult) => {
console.log("res.tempImagePath", res.tempImagePath);
this.imageSrc = res.tempImagePath ?? ''
},
fail: (e : any) => {
console.log("take photo", e);
}
} as CameraContextTakePhotoOptions)
},
takePhotoQualityChange(event : UniRadioGroupChangeEvent) {
this.quality = event.detail.value
console.log("quality", this.quality);
},
setOnFrameListener() {
const context = uni.createCameraContext();
this.listener = context?.onCameraFrame((frame : CameraContextOnCameraFrame) => {
console.log("OnFrame :", frame);
})
},
startFrameListener() {
this.listener?.start({
success: (res : any) => {
console.log("startFrameListener success", res);
}
} as CameraContextCameraFrameListenerStartOptions)
},
stopFrameListener() {
this.listener?.stop({
success: (res : any) => {
console.log("stopFrameListener success", res);
}
} as CameraContextCameraFrameListenerStopOptions)
},
startRecord() {
const context = uni.createCameraContext();
let timeout = this.getTimeout()
this.timeout = timeout
context?.startRecord({
timeout: timeout,
selfieMirror: false,
timeoutCallback: (res : any) => {
console.log("timeoutCallback", res);
this.startRecordStatus = false
if (typeof res != "string") {
const result = res as CameraContextStartRecordTimeoutResult
this.videoSrc = result.tempVideoPath ?? ''
}
clearInterval(this.intervalId)
},
success: (res : any) => {
this.startRecordStatus = true
console.log("start record success", res);
this.remain = timeout
this.intervalId = setInterval(() => {
if (this.remain <= 0) {
clearInterval(this.intervalId)
} else {
this.remain--
}
}, 1000)
},
fail: (res : any) => {
console.log("start record fail", res);
this.startRecordStatus = false
this.remain = 0
clearInterval(this.intervalId)
}
} as CameraContextStartRecordOptions)
},
stopRecord() {
this.startRecordStatus = false
const context = uni.createCameraContext();
context?.stopRecord({
compressed: this.compressed,
success: (res : CameraContextStopRecordResult) => {
console.log("stop record success", res);
this.videoSrc = res.tempVideoPath ?? ''
},
fail: (res : any) => {
console.log("stop record fail", res);
}
} as CameraContextStopRecordOptions)
clearInterval(this.intervalId)
this.remain = 0
},
startRecordCompressChange(event : UniRadioGroupChangeEvent) {
this.compressed = parseInt(event.detail.value) == 1
},
timeoutInput(event : UniInputEvent) {
this.timeoutStr = event.detail.value
},
getTimeout() : number {
let value = parseInt(this.timeoutStr)
// #ifdef APP-ANDROID
if (value == NaN) {
// #endif
// #ifndef APP-ANDROID
if (value !== value) {
// #endif
return 30
} else {
if (value < 1) {
return 1
} else if (value > 60 * 5) {
return 60 * 5
} else {
return value
}
}
}
}
}
</script>
<style>
.uni-title {
padding: 10px 0;
}
.uni-title-text {
font-size: 15px;
font-weight: bold;
}
.uni-camera-wrapper {
display: flex;
padding: 8px 13px;
margin: 5px 0;
flex-direction: row;
flex-wrap: nowrap;
background-color: #ffffff;
}
.uni-camera-test-host {
height: 28px;
padding: 0px;
flex: 1;
background-color: #ffffff;
}
.uni-camera-test-host-without-flex {
height: 28px;
padding: 0px;
background-color: #ffffff;
}
.uni-title-size {
font-size: 22px;
}
</style>