前端如何在PC实现拍照上传功能

 最近有一个需求,PC实现拍照上传图片的功能,研究了一段时间,最终自己实现了,下面记录一下。

<template>
  <div class="content">
    <div class="notice">注意:未成年请与监护人一起完成拍照,同时避开隐私部位</div>

    <div class="wrapper">
      <div class="item">
        <div class="title">
          请确保当前设备的摄像头处于可用状态
        </div>
        <div class="avatar">
          <img style="display: none" ref="photo" />
          <video ref="video" style="width: 100%; height: 100%" muted></video>
        </div>

        <div class="btn">
          <el-button type="primary" size="small" @click="handleCapture">拍照</el-button>
        </div>
      </div>
      <div class="item">
        <div class="title">照片预览</div>
        <div class="avatar">
          <canvas ref="canvas" style="width: 100%; height: 100%"></canvas>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { ref, nextTick, onMounted } from 'vue';
  import { ElMessage } from 'element-plus';

  const video = ref();
  const photo = ref();
  const canvas = ref();
  const context = ref();
  // 图片
  const base64Img = ref();

  // 访问用户媒体设备的兼容方法
  function getUserMedia(constraints, success, error) {
    if (navigator.mediaDevices.getUserMedia) {
      // 最新的标准 API
      navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
    } else if (navigator.webkitGetUserMedia) {
      // webkit 核心浏览器
      navigator.webkitGetUserMedia(constraints, success, error);
    } else if (navigator.mozGetUserMedia) {
      // firefox 浏览器
      navigator.mozGetUserMedia(constraints, success, error);
    } else if (navigator.getUserMedia) {
      // 旧版 API
      navigator.getUserMedia(constraints, success, error);
    }
  }

  /*
   * 定义数据
   * */
  const emit = defineEmits(['update:confirm']);

  // 打开弹出层
  const openDialog = async (row) => {
    await nextTick();

    canvas.value.width = 360;
    canvas.value.height = 360;
    context.value = canvas.value.getContext('2d');

    initPhoto();
  };

  // 保存
  const save= async () => {
    if (!base64Img.value) {
      return ElMessage.error('请拍照');
    }
    try {
      const img = base64Img.value.replace('data:image/png;base64,', '');
      emit('update:confirm', img);
      // 根据后端返回的响应进行相应的处理
    } catch (error) {
      console.error('保存图片时出错', error);
    }
  };

  /*
   * 关闭弹出层
   * */
  function onClose() {}

  function success(stream) {
    //兼容webkit核心浏览器
    let CompatibleURL = window.URL || window.webkitURL;
    //将视频流设置为video元素的源
    console.log(stream);

    //video.src = CompatibleURL.createObjectURL(stream);
    video.value.srcObject = stream;
    video.value.play();
  }

  function error(error) {
    ElMessage.warning('访问用户媒体设备失败');
  }

  // 点击拍照
  const handleCapture = () => {
    context.value.drawImage(video.value, 0, 0, 360, 360);
    context.value.getImageData(0, 0, 360, 360);
    //导出
    base64Img.value = canvas.value.toDataURL('image/jpg');
  };

  // 初始化摄像头
  const initPhoto = () => {
    if (
      navigator.mediaDevices?.getUserMedia ||
      navigator.getUserMedia ||
      navigator.webkitGetUserMedia ||
      navigator.mozGetUserMedia
    ) {
      //调用用户媒体设备, 访问摄像头
      getUserMedia(
        {
          video: {
            width: 360,
            height: 360,
          },
        },
        success,
        error,
      );
    } else {
      alert('不支持访问用户媒体');
    }
  };

  // 导出方法
  defineExpose({
    openForm,
  });
</script>

<style lang="scss" scoped>
  .content {
    padding: 0 60px;

    .notice {
      height: 40px;
      line-height: 40px;
      margin-bottom: 20px;
      padding: 0 16px;
      color: #f56c6c;
      font-size: 14px;
      background-color: #fef0f0;
      border-radius: 2px;
    }

    .wrapper {
      display: flex;
      justify-content: space-between;

      .item {
        width: 400px;
        height: 442px;
        padding: 8px 20px;
        border: 1px solid #eeeeee;

        .title {
          display: flex;
          justify-content: space-between;
          margin-bottom: 8px;

          div {
            display: flex;
            align-items: center;
            color: #3060b9;

            .el-icon {
              margin-right: 4px;
            }
          }
        }

        .avatar {
          width: 100%;
          height: 360px;
        }

        .btn {
          display: flex;
          justify-content: center;
          margin-top: 8px;
        }

        &:last-child {
          .title {
            justify-content: center;
          }
        }
      }
    }
  }
</style>

写完之后可能还是不行,需要再http协议下开启安全域名权限

chrome浏览器打开:chrome://flags/#unsafely-treat-insecure-origin-as-secure
edge浏览器打开:edge://flags/#unsafely-treat-insecure-origin-as-secure

在输入框中输入需要访问的地址,多个地址使用“,”隔开,重新启动即可

自动重启浏览器之后就可以在添加的http地址下调用摄像头和麦克风了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值