H5 页面通过navigator.mediaDevices.getUserMedia调用手机摄像头拍照上传

需求: 某知名化妆品牌,要做个在线问卷调查。需要试用着自拍上传

注:使用navigator.mediaDevices.getUserMedia 需要使用https请求协议否者视为不安全,无法访问,开发阶段需要将启动改为https 在package.json中

前端开发环境启动项目将http协议改为https协议

H5 页面通过navigator.mediaDevices.getUserMedia调用手机摄像头拍照上传_第1张图片H5 页面通过navigator.mediaDevices.getUserMedia调用手机摄像头拍照上传_第2张图片H5 页面通过navigator.mediaDevices.getUserMedia调用手机摄像头拍照上传_第3张图片

 

 授权,默认前置,切换后置

注意切换摄像头时要注意,一定要像关闭摄像头不然会有问题在部分手机上

import {
  Button,
  Dialog,
  ImageUploader,
  Modal,
  Popup,
  Toast,
} from 'antd-mobile';
import React, { useEffect, useState } from 'react';
import { useRef } from 'react';
import { history } from 'umi';
import {
  uploadFile,
  getProjectInfo,
  saveUploadFile,
  deleteFile,
  getQuestionsByResultId,
} from '@/app/request/requestApi'; // 接口
import { ImageUploadItem } from 'antd-mobile/es/components/image-uploader';
import { CameraOutline, ExclamationCircleFill } from 'antd-mobile-icons';
import './style.less';

const index = (props: any) => {
  const [fileList, setFileList] = useState([]);
  const [projectInfo, setProjectInfo] = useState({});
  const [visible, setVisible] = useState(false);
  const [rotvisible, setRotVisible] = useState(false);
  const [direction, setDirection] = useState(0);
  const [language, setLanguage] = useState('ZH');

  useEffect(() => {
    setLanguage(localStorage.getItem('language') ?? 'ZH');
  }, []);

  useEffect(() => {
    setTimeout(() => {
      document.getElementsByTagName('title')[0].text = '上传图片';
    }, 500);
    getProjectInfo().then((res) => {
      if (res.success) {
        localStorage.setItem('projectInfo', JSON.stringify(res.data));
        setProjectInfo(res.data);
      } else {
        Dialog.alert({
          content: res.msg,
          onConfirm: () => {
            history.push('../');
          },
        });
      }
    });
  }, []);
  useEffect(() => {
    if (!visible) {
       // 关闭
      if (document.getElementById('video')?.srcObject) {
        document.getElementById('video').srcObject.getTracks()[0].stop();
      }
      return;
    }
    if (
      //@ts-ignore
       // 开启
      navigator.mediaDevices.getUserMedia ||
      navigator.getUserMedia ||
      navigator.webkitGetUserMedia ||
      navigator.mozGetUserMedia ||
      navigator.msGetUserMedia ||
      navigator.oGetUserMedia
    ) {
      var facingMode: any = null;
      if (direction == 1) {
        facingMode = { exact: 'environment' };
      } else {
        facingMode = { exact: 'user' };
      }
      // 切换摄像头需先关闭再打开
      if (document.getElementById('video')?.srcObject) {
        document.getElementById('video').srcObject.getTracks()[0].stop();
      }
      //调用用户媒体设备, 访问摄像头
      getUserMedia(
        { video: { width: 480, height: 320, facingMode: facingMode } }, // user 前置
        success,
        error,
      );
    } else {
      alert('不支持访问用户媒体');
    }
  }, [visible, direction]);
  let model: any = localStorage.getItem('model');
  const onUpload = async (file: any) => {
    let formData = new FormData();
    formData.append('projectId', projectInfo.projectId);
    formData.append('projectTimeId', projectInfo.timeId);
    formData.append('phone', model);
    formData.append('fileInfos', file);
    var res = await uploadFile(formData);
    if (res.success) {
      return {
        url: res.data[0].imageUrl,
      } as ImageUploadItem;
    } else {
      Dialog.alert({
        content: res.msg,
        onConfirm: () => {
          //history.push("../");
        },
      });
      return {
        url: URL.createObjectURL(file),
      } as ImageUploadItem;
    }
  };

  const getUserMedia = (constraints: any, success: any, error: any) => {
    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) {
      //firfox浏览器
      navigator.mozGetUserMedia(constraints, success, error);
    } else if (navigator.getUserMedia) {
      //旧版API
      navigator.getUserMedia(constraints, success, error);
    }
  };

  const success = (stream: any) => {
    //兼容webkit核心浏览器
    let CompatibleURL = window.URL || window.webkitURL;
    //将视频流设置为video元素的源
    let videoElement = document.getElementById('video');
    //@ts-ignore
    videoElement.srcObject = stream;
    //@ts-ignore
    videoElement.play();
  };

  const error = (error: any) => {
    alert(`访问用户媒体设备失败${error.name}, ${error.message}`);
    console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
  };

  return (
    <>
      {projectInfo.projectName}
       {
          console.log(item);
          return Dialog.confirm({
            content: '是否确认删除',
          }).then((res) => {
            if (!res) {
              return false;
            } else {
              return deleteFile({
                id: item.id,
              }).then((res) => {
                if (res.success) {
                  return true;
                } else {
                  Dialog.alert({
                    content: res.msg,
                    onConfirm: () => {
                      //history.push('../');
                    },
                  });
                  return false;
                }
              });
            }
          });
        }}
        onChange={(files) => {
          setFileList(files);
        }}
        disableUpload={true}
        upload={onUpload}
        children={
          
{ Dialog.alert({ content: language == 'ZH' ? '请摘掉眼镜,露出额头和耳朵,在光线明亮的地方,原地旋转每30度左右拍一张,共6张' : 'Please take off your glasses, expose your forehead and ears, and take a picture every 60 degrees or so in a bright place. A total of 6 pictures', onConfirm: () => { setVisible(true); }, }); }} style={{ fontSize: 32 }} />
} />
{language == 'ZH' ? '上传图片需最少六张图片才可进入下一步' : 'A minimum of six images are required to upload images to proceed to the next step'}
{ setVisible(false); }} forceRender={true} position="top" bodyStyle={{ minWidth: '100%', minHeight: '100%', backgroundColor: 'black', }} >
// 切换摄像头 { setDirection(direction == 1 ? 0 : 1); console.log('切换摄像头'); }} style={{ fontSize: '30px', lineHeight: '60px', color: 'white' }} />
// video 视频 // 拍照截取当前帧绘制到画布上
// 主要是获取摄像头的视频流并显示在Video 签中 { var canvas = document.getElementById('canvas'); canvas.width = document.getElementById('video')?.offsetWidth; canvas.height = document.getElementById('video')?.offsetHeight; //@ts-ignore canvas ?.getContext('2d') ?.drawImage( document.getElementById('video'), 0, 0, document.getElementById('video')?.offsetWidth, document.getElementById('video')?.offsetHeight, ); canvas.getContext('2d')?.canvas.toBlob( (blob: any) => { let files = new window.File( [blob], new Date().getTime() + '.jpg', ); let formData = new FormData(); formData.append('projectId', projectInfo.projectId); formData.append('projectTimeId', projectInfo.timeId); formData.append( 'phone', model, // navigator.userAgent.split('AppleWebKit')[0], ); formData.append('fileInfos', files); setVisible(false); uploadFile(formData).then((res) => { if (res.success) { setFileList([ ...fileList, { key: new Date().getTime(), url: URL.createObjectURL(files), id: res.data[0].id, }, ]); } else { Dialog.alert({ content: res.msg, onConfirm: () => {}, }); } }); }, 'image/jpeg', 0.7, ); //@ts-ignore var cutAvater = canvas.getContext('2d')?.canvas.toDataURL(0.7); var arr = cutAvater?.split(','); //@ts-ignore var data = window.atob(arr[1]); //@ts-ignore var mime = arr[0].match(/:(.*?);/)[1]; var ia = new Uint8Array(data.length); for (var i = 0; i < data.length; i++) { ia[i] = data.charCodeAt(i); } var blob = new Blob([ia], { type: 'image/jpeg' }); }} className="camerBtn" />
); }; export default index;

main {
  padding: 24px 24px 16px;
  display: flex;
}

video {
  margin-right: 16px;
  box-sizing: content-box;
  //border: 4px solid #ffaabb;
}

canvas {
  box-sizing: content-box;
  border: 4px solid #aabbff;
}

.actions {
  padding: 0 24px;
}

.actions button {
  margin-right: 16px;
}

.imgSuccess {
  width: 142px;
  height: 119px;
  background: url('../../../assets/images/success.png') no-repeat;
  background-size: 100%;
  border: 1px dashed gray;
}

.projectTitle {
  display: block;
  font-size: 26px;
  color: #b18b35;
  font-weight: bold;
  font-family: 'MicrosoftYaHei-Bold';
  margin: 20px 0 21px 20px;
}

.adm-image-uploader .adm-space-item {
  width: 100px;
  height: 100px;
  border: 1px dashed black;
  padding-bottom: 0px !important;
  margin-top: 10px;
}

.adm-image-uploader {
  margin-bottom: 40px;
}
.adm-image-uploader {
  margin-left: 20px;
}

.adm-text-area-element {
  background-color: #ffffff !important;
}

.btnNext {
  color: white;
  font-size: 12px;
  font-weight: bold;
  background-color: #b18b34;
  border: none;
  width: 236px;
  height: 39px;
  border-radius: 18px;
}

.adm-image-img {
  // width: auto;
  // height: 100%;
  // margin:0 auto;
}

.camerBtn {
  font-size: 60px;
  color: white;
}

.divBtn {
  position: absolute;
  bottom: 0px;
  width: 100%;
  height: 80px;
  text-align: center;
}

你可能感兴趣的:(javascript,react.js,前端,开发语言)