Skip to content
vue
<script setup>
import {onMounted, ref} from "vue";
import {ElMessage} from "element-plus";

let video = ref();
let canvas = ref();
let result = ref();

// 初始化
async function init() {
    video.value = document.getElementById('video');
    canvas.value = document.getElementById('canvas');

    try {
        video.value.srcObject = await navigator.mediaDevices.getUserMedia({
            video: {
                facingMode: '',
                width: {ideal: 40000},
                height: {ideal: 30000},
                frameRate: {ideal: 60},
            },
            audio: false
        });
    } catch (err) {
        ElMessage.warning('摄像头访问失败');
        console.log('摄像头访问失败', err);
    }
}

// 拍照
function takePicture() {
    if (result.value) {
        result.value = null;
        return;
    }
    let context = canvas.value.getContext('2d');
    canvas.value.width = video.value.videoWidth;
    canvas.value.height = video.value.videoHeight;
    context.drawImage(video.value, 0, 0, canvas.value.width, canvas.value.height);
    context.setTransform(1, 0, 0, 1, 0, 0);
    result.value = canvas.value.toDataURL('image/png', 1);
}

onMounted(() => {
    init();
})
</script>

<template>
    <div class="camera">
        <img class="result" :src="result" v-if="result" />
        <div class="medium" v-show="!result">
            <video id="video" autoplay playsinline />
            <canvas id="canvas" />
        </div>
        <el-button type="primary" @click="takePicture">{{result ? '重新拍照' : '点击拍照'}}</el-button>
    </div>
</template>

<style scoped>
.camera {
    height: 500px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;

    .result {
        height: 100%;
    }

    .medium {
        height: 100%;

        #video {
            width: 100%;
            height: 100%;
            border-right: 4px;
        }

        #canvas {
            display: none;
        }
    }
}
</style>

基于 MIT 许可发布