h5调用摄像头和本地文件选择图片

前言

使用vue2+js语法

通过navigator.mediaDevices.getUserMedia()访问摄像头,但需要在localhost或https下才可以正常访问,否则没有权限。

通过input标签在浏览器环境访问本地文件图片;

拍照通过canvas的drawImage绘制video视频帧,再通过toDataURL将绘制的canvas转换为图片,获取到图片的base64码;获取本地图片同样获取base64码;

实现效果

完整代码

xml 复制代码
<template>
  <div>
    <!-- 已上传图片展示 -->
    <div id="uploader_img">
      <div v-for="(item, index) in imglists" :key="item.name" class="img-box">
        <div class="img-item">
          <div class="img-item-img">
            <img :src="item.url" alt="" class="img-item-img-content" />
          </div>

          <div class="img-info">
            <div class="img-name">{{ item.name }}</div>
            <div class="img-size">{{ item.size }}</div>
          </div>
        </div>
        <div @click="deleteImg(imglists, index)" class="img-delete">
          <!-- 删除按钮 -->
          <svg
            t="1744701515127"
            class="icon delete_btn"
            viewBox="0 0 1024 1024"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            p-id="2626"
            width="200"
            height="200"
          >
            <path
              d="M512 177.980952c-181.638095 0-329.142857 147.504762-329.142857 329.142858s147.504762 329.142857 329.142857 329.142857 329.142857-147.504762 329.142857-329.142857-147.504762-329.142857-329.142857-329.142858z m140.190476 425.447619L608.304762 646.095238 512 549.790476 415.695238 646.095238l-42.666667-42.666667 96.304762-96.304761-96.304762-96.304762 42.666667-42.666667L512 463.238095l96.304762-96.304762 42.666667 42.666667-96.304762 96.304762 97.523809 97.523809z"
              fill="#bfbfbf"
              p-id="2627"
            ></path>
          </svg>
        </div>
      </div>
    </div>
    <!-- 点击上传 - 长框 -->
    <div
      @click="startCamera"
      :class="{ 'upload-box': !isShowCamera, 'upload-box-none': isShowCamera }"
    >
      <div>
        <svg
          t="1744621394979"
          class="icon uploader_clibtn"
          viewBox="0 0 1024 1024"
          version="1.1"
          xmlns="http://www.w3.org/2000/svg"
          p-id="2846"
          width="200"
          height="200"
        >
          <path
            d="M536.380952 288.377905V658.285714a24.380952 24.380952 0 0 1-48.761904 0V288.377905L391.314286 384.731429a24.380952 24.380952 0 0 1-34.474667-34.474667l137.898667-137.898667a24.283429 24.283429 0 0 1 34.523428 0l137.898667 137.898667a24.380952 24.380952 0 0 1-34.474667 34.474667L536.380952 288.377905zM97.52381 731.428571a24.380952 24.380952 0 0 1 48.761904 0v97.52381a24.380952 24.380952 0 0 0 24.380953 24.380952h682.666666a24.380952 24.380952 0 0 0 24.380953-24.380952v-97.52381a24.380952 24.380952 0 0 1 48.761904 0v97.52381a73.142857 73.142857 0 0 1-73.142857 73.142857H170.666667A73.142857 73.142857 0 0 1 97.52381 828.952381v-97.52381z"
            fill="#9DA7B2"
            p-id="2847"
          ></path>
        </svg>
      </div>

      <div>点击上传</div>
    </div>
    <!-- 点击上传 - 方框 -->
    <div @click="startCamera" style="display: none">
      <svg
        t="1744178513446"
        class="icon uploader_squarebtn"
        viewBox="0 0 1024 1024"
        version="1.1"
        xmlns="http://www.w3.org/2000/svg"
        p-id="12086"
        width="200"
        height="200"
      >
        <path
          d="M997.28 56l-27.712 16A47.968 47.968 0 0 0 928 48v-32c28.864 0 55.072 15.456 69.28 40z m10.72 134.048h-32v-64h32v64z m0 128h-32v-64h32v64z m0 128h-32v-64h32v64z m0 128h-32v-64h32v64z m0 128h-32v-64h32v64z m0 128h-32v-64h32v64z m-8.8 134.464l-28.48-14.624c3.456-6.72 5.28-14.144 5.28-21.888v-33.952h32V928c0 12.864-3.04 25.28-8.8 36.48zM867.936 1008v-32h60.288l2.976-0.096 2.08 31.936-2.464 0.096-62.88 0.064z m-128 0v-32h64v32h-64z m-128 0v-32h64v32h-64z m-128 0v-32h64v32h-64z m-128 0v-32h64v32h-64z m-128 0v-32h64v32h-64z m-128 0v-32h64v32h-64zM16 901.888h32V928c0 9.728 2.88 18.976 8.192 26.88l-26.496 17.92A79.68 79.68 0 0 1 16 928v-26.112z m0-128h32v64h-32v-64z m0-128h32v64h-32v-64z m0-128h32v64h-32v-64z m0-128h32v64h-32v-64z m0-128h32v64h-32v-64z m0-128h32v64h-32v-64zM86.976 16.512l3.584 31.776c-17.088 1.92-31.776 12.928-38.592 28.544l-29.344-12.8A80.064 80.064 0 0 1 86.976 16.544zM216.128 16v32h-64v-32h64z m128 0v32h-64v-32h64z m128 0v32h-64v-32h64z m128 0v32h-64v-32h64z m128 0v32h-64v-32h64z m128 0v32h-64v-32h64zM928 16v32h-7.872v-32H928z"
          fill="#8a8a8a"
          p-id="12087"
        ></path>
        <path d="M255.872 544v-32h480v32z" fill="#8a8a8a" p-id="12088"></path>
        <path d="M479.872 288h32v480h-32z" fill="#8a8a8a" p-id="12089"></path>
      </svg>
    </div>
    <!-- 弹框选择:相册/拍照 -->
    <div id="myModal" class="choose_modal">
      <div class="choosemodal-content">
        <div class="choosemodal-option" id="openCamera" @click="openCamera">
          打开相机
        </div>
        <div class="choosemodal-option" id="openAlbum" @click="openAlbum">
          打开相册
        </div>
      </div>
    </div>
    <!-- 本地文件选择 仅相册 -->
    <input
      type="file"
      id="fileInput"
      accept="image/png,image/jpeg"
      capture="filesystem"
      hidden
    />
    <!-- 相机拍照界面 -->
    <div id="cameraModal" class="camera_modal">
      <!-- 相机拍照界面 -->
      <div v-show="!isCapture">
        <div class="camera-container">
          <video id="video" autoplay playsinline></video>

          <!-- 人像框图片 -->
          <div class="frame">
            <svg
              t="1744250348203"
              class="icon camera_portrait"
              viewBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="38048"
              width="200"
              height="200"
            >
              <path
                d="M953 965.52a5.52 5.52 0 0 1-4.75-2.71c-6.03-10.24-13.6-18.69-23.15-25.84-15.75-11.78-34.15-21.8-54.67-29.78-20.81-8.09-42.51-15.34-64.51-21.53-22.29-6.26-43.23-13.44-62.24-21.32-21.62-8.82-38.73-19.05-50.83-30.4-12.15-11.39-21.31-23.6-27.22-36.29-5.92-12.71-9.33-25.61-10.11-38.34-0.78-12.46 0-24.93 2.33-37.05 3.21-20.68 9.88-35.75 19.81-44.77 8.97-8.15 20.8-18.25 35.15-30 5.46-4.97 10.53-12.09 15.08-21.17 4.76-9.49 9.04-19.33 12.72-29.25 3.72-11.58 7.49-24.1 11.22-37.23l0.81-2.87 2.85-0.88c6.72-2.08 13.24-6.02 19.38-11.69 5.53-5.02 10.63-12.17 15.2-21.29 4.57-9.1 7.61-21.66 9.05-37.33l0.02-0.16c1.43-11.83 1.27-21.87-0.47-29.84-1.78-8.07-4.06-14.68-6.79-19.63l-0.14-0.27c-2.65-5.5-6.17-9.82-10.76-13.22l-2.23-1.65v-2.77c0-31.71-1.89-63.46-5.61-94.35-3.7-26.84-10.1-55.56-19.03-85.29-8.81-29.32-22.96-56.53-42.03-80.88-7.99-10.55-19.22-21.23-33.44-31.82-14.3-10.66-30.89-20.32-49.31-28.73-18.41-8.41-38.42-15.2-59.47-20.18-20.97-4.96-42.41-7.47-63.74-7.47-16.99 0-34.79 1.36-52.9 4.05-17.91 2.65-36.09 7.85-54.06 15.45-17.96 7.61-35.81 18.23-53.05 31.55-17.15 13.25-32.9 30.76-46.81 52.03l-0.09 0.14c-15.39 22.03-27.1 47.51-34.82 75.71-7.79 28.51-13.26 55.47-16.23 80.14-3.72 29.35-5.23 59.06-4.48 88.34l0.05 2.13-1.4 1.61c-6.29 7.26-10.89 14.95-13.67 22.85l-0.06 0.15c-2.83 7.36-4.81 16.35-5.88 26.74-1.04 10.1 0.58 21.55 4.83 34.02l0.08 0.27c3.57 12.58 7.83 22.23 12.68 28.69 4.95 6.6 9.57 11.79 13.74 15.42 4.69 3.45 9.38 5.88 13.95 7.23l2.91 0.86 0.83 2.92c3.72 13.12 7.5 25.65 11.22 37.23 3.68 9.91 7.8 19.8 12.23 29.4 4.17 9.02 9.04 16.11 14.48 21.05 12.85 10.97 24.72 21.91 35.3 32.5 11.44 11.44 18.07 27 19.68 46.24l0.01 0.13c0.76 12.61 1.14 24.17 1.14 34.34 0 10.83-2.03 21.39-6.05 31.37-3.99 9.93-10.41 19.94-19.07 29.74-8.57 9.71-21.13 19.91-37.33 30.31-20.7 13.52-44.82 24.02-71.65 31.18-26.04 6.94-51.55 14.98-75.84 23.89-23.79 8.73-44.94 20.65-62.84 35.44-6.81 5.62-12.47 12.23-17.3 20.19a5.508 5.508 0 0 1-7.56 1.85 5.508 5.508 0 0 1-1.85-7.56c5.48-9.04 11.93-16.55 19.7-22.97 18.87-15.58 41.09-28.12 66.06-37.28 24.6-9.03 50.44-17.17 76.8-24.19 25.7-6.86 48.75-16.88 68.51-29.78 15.38-9.88 27.16-19.42 35.06-28.36 7.83-8.86 13.59-17.8 17.11-26.56 3.49-8.67 5.25-17.85 5.25-27.27 0-9.94-0.38-21.25-1.12-33.62-1.4-16.54-6.95-29.77-16.49-39.31-10.4-10.41-22.08-21.16-34.73-31.97l-0.12-0.11c-6.55-5.94-12.31-14.23-17.13-24.63-4.57-9.9-8.81-20.09-12.6-30.31l-0.08-0.23c-3.51-10.91-7.06-22.64-10.57-34.92-4.89-1.81-9.79-4.52-14.61-8.09l-0.33-0.26c-4.8-4.15-10.02-9.97-15.5-17.28-5.72-7.62-10.44-18.14-14.42-32.15-4.72-13.94-6.51-26.91-5.31-38.56 1.17-11.32 3.36-21.24 6.53-29.48 3.03-8.58 7.84-16.88 14.31-24.69-0.64-29.15 0.91-58.71 4.61-87.87 3.04-25.16 8.6-52.66 16.54-81.69 8.05-29.39 20.28-55.99 36.37-79.04 14.57-22.27 31.14-40.65 49.24-54.64 17.99-13.9 36.66-24.99 55.49-32.97 18.83-7.97 37.92-13.42 56.74-16.21 18.65-2.77 36.99-4.17 54.51-4.17 22.18 0 44.48 2.61 66.28 7.77 21.76 5.15 42.45 12.17 61.51 20.88 19.12 8.72 36.39 18.79 51.31 29.91 15.05 11.21 27.02 22.63 35.58 33.93 19.87 25.36 34.64 53.79 43.85 84.43 9.09 30.27 15.62 59.55 19.4 87.04 3.68 30.56 5.59 61.83 5.7 93.1 4.9 4.14 8.87 9.3 11.83 15.39 3.25 5.93 5.82 13.28 7.83 22.46 2 9.16 2.22 20.4 0.66 33.43-1.57 17.01-4.99 30.86-10.16 41.18-5.18 10.34-11.11 18.58-17.61 24.48-6.47 5.97-13.42 10.38-20.67 13.1-3.51 12.29-7.07 24.03-10.58 34.94l-0.08 0.23a304.982 304.982 0 0 1-13.24 30.46c-5.19 10.35-11.12 18.59-17.63 24.48l-0.21 0.18c-14.26 11.68-25.98 21.68-34.84 29.73-8.04 7.3-13.54 20.23-16.35 38.41l-0.04 0.2c-2.17 11.24-2.9 22.81-2.17 34.39 0.7 11.36 3.77 22.93 9.11 34.38 5.32 11.41 13.66 22.49 24.78 32.91 11.12 10.42 27.1 19.93 47.5 28.25 18.63 7.73 39.16 14.76 61.03 20.91 22.34 6.29 44.38 13.65 65.52 21.87 21.45 8.34 40.72 18.85 57.27 31.22 10.59 7.92 19.36 17.7 26.05 29.07 1.54 2.62 0.67 5.99-1.95 7.53-0.91 0.51-1.87 0.75-2.81 0.75z"
                fill="#1296db"
                p-id="38049"
              ></path>
            </svg>
          </div>
          <!-- <img src="https://ss-mpvolc.meipian.me/users/24620570/36a3481767dc4fbc9654cc87c008daeb__jpg.heic~tplv-s1ctq42ewb-s3-cC-q:750:0:0:0:q80.webp" alt="人像框" class="frame"> -->
        </div>
        <div class="camera-container">
          <!-- 返回上传页面 -->
          <div @click="backToUpload" id="back-to-upload">
            <svg
              t="1744709693613"
              class="icon capture_btn_other"
              viewBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="3443"
              width="200"
              height="200"
            >
              <path
                d="M648 307.2H217.6l128-128c12.8-12.8 12.8-32 0-44.8-12.8-12.8-32-12.8-44.8 0L118.4 315.2c-6.4 6.4-9.6 14.4-9.6 22.4s3.2 16 9.6 22.4l180.8 180.8c12.8 12.8 32 12.8 44.8 0 12.8-12.8 12.8-32 0-44.8l-124.8-124.8h428.8c120 0 216 96 216 216s-96 216-216 216H320c-17.6 0-32 14.4-32 32s14.4 32 32 32h328c155.2 0 280-124.8 280-280s-124.8-280-280-280z"
                fill="#ffffff"
                p-id="3444"
              ></path>
            </svg>
          </div>
          <div id="capture-btn" @click="capture">
            <!-- 拍照按钮 -->
            <div id="capture-out">
              <div id="capture-inner"></div>
            </div>
          </div>
          <div></div>
        </div>
      </div>

      <canvas id="canvas" class="isnone"></canvas>
      <!-- 拍照后的图片展示 -->
      <div v-show="isCapture" class="camera-container">
        <div id="capture-img"></div>
        <div id="capture_img_result">
          <!-- 返回上传页面 -->
          <div @click="backToUpload">
            <svg
              t="1744709693613"
              class="icon capture_btn_other"
              viewBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="3443"
              width="200"
              height="200"
            >
              <path
                d="M648 307.2H217.6l128-128c12.8-12.8 12.8-32 0-44.8-12.8-12.8-32-12.8-44.8 0L118.4 315.2c-6.4 6.4-9.6 14.4-9.6 22.4s3.2 16 9.6 22.4l180.8 180.8c12.8 12.8 32 12.8 44.8 0 12.8-12.8 12.8-32 0-44.8l-124.8-124.8h428.8c120 0 216 96 216 216s-96 216-216 216H320c-17.6 0-32 14.4-32 32s14.4 32 32 32h328c155.2 0 280-124.8 280-280s-124.8-280-280-280z"
                fill="#ffffff"
                p-id="3444"
              ></path>
            </svg>
          </div>
          <!-- 选择当前拍照图片 -->
          <div @click="chooseCurrentCapture">
            <svg
              t="1744709761210"
              class="icon capture_btn_other"
              viewBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="4467"
              width="200"
              height="200"
            >
              <path
                d="M939.36 218.912a32 32 0 0 1 45.856 44.672l-538.016 552a32 32 0 0 1-43.776 1.92L63.872 526.048a32 32 0 1 1 41.696-48.544l316.768 271.936L939.36 218.88z"
                fill="#ffffff"
                p-id="4468"
              ></path>
            </svg>
          </div>
          <!-- 取消当前拍照图片 - 重新拍照 -->
          <div @click="reCapture">
            <svg
              t="1744709781811"
              class="icon capture_btn_other"
              viewBox="0 0 1024 1024"
              version="1.1"
              xmlns="http://www.w3.org/2000/svg"
              p-id="5521"
              width="200"
              height="200"
            >
              <path
                d="M842.947458 778.116917 576.847937 512.013303 842.946434 245.883083c8.67559-8.674567 13.447267-20.208251 13.43908-32.477692-0.008186-12.232602-4.7727-23.715121-13.414521-32.332383-8.655124-8.677637-20.149922-13.450337-32.384571-13.4575-12.286838 0-23.808242 4.771677-32.474622 13.434987L512.019443 447.143876 245.88206 181.050496c-8.66331-8.66331-20.175505-13.434987-32.416294-13.434987-12.239765 0-23.75196 4.770653-32.414247 13.43294-8.66024 8.636704-13.428847 20.12434-13.437034 32.356942-0.008186 12.269441 4.76349 23.803125 13.437034 32.476669l266.135336 266.13022L181.050496 778.11794c-8.664334 8.66331-13.43601 20.173458-13.43601 32.41527 0 12.239765 4.7727 23.752983 13.437034 32.417317 8.662287 8.66331 20.173458 13.43294 32.413224 13.43294 12.240789 0 23.754007-4.770653 32.416294-13.43294l266.134313-266.100544 266.101567 266.100544c8.66331 8.66331 20.185738 13.43294 32.4429 13.43294 12.265348-0.008186 23.74889-4.771677 32.369222-13.412474C860.81643 825.081555 860.821547 795.991006 842.947458 778.116917z"
                fill="#ffffff"
                p-id="5522"
              ></path>
            </svg>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: "CustomUpload",
  data() {
    return {
      //  预览图片
      previewImage: null,
      //  预览视频
      previewVideo: null,

      // 视频流
      mediaStream: null,

      //  点击上传
      isShowCamera: false,
      // 选择弹框
      chooseModal: null,
      // 相机弹框
      cameraModal: "block",
      // video元素
      videoDom: null,
      // canvas元素
      canvasDom: null,
      // 拍照图片
      imglistDom: null,
      // 拍照图片显示
      uploaderImgDom: null,
      // 拍照图片列表
      imglists: [],
      // 点击拍照按钮
      isCapture: false,
      // 当前拍照图片url
      currentCaptureImg: null,
    };
  },
  methods: {
    init() {
      this.chooseModal = document.getElementById("myModal");
      this.cameraModal = document.getElementById("cameraModal");
      this.videoDom = document.getElementById("video");
      this.canvasDom = document.getElementById("canvas");
      this.imglistDom = document.getElementById("capture-img");
      this.uploaderImgDom = document.getElementById("uploader_img");
      this.getAlbumImgInfo();
    },
    // 点击任意位置关闭弹框
    closeChooseModal() {
      let modal = this.chooseModal;
      // 点击任意位置关闭弹框
      window.onclick = function (event) {
        if (event.target == modal) {
          modal.style.display = "none";
        }
      };
    },
    // 点击上传-打开选择弹框
    openChooseModal() {
      let modal = this.chooseModal;
      modal.style.display = "block";
    },
    // 点击上传
    startCamera() {
      this.openChooseModal();
    },
    // 关闭选择弹框
    closeModal() {
      let modal = this.chooseModal;
      modal.style.display = "none";
    },
    // 打开相册
    openAlbum() {
      console.log("打开相册", window, window.nativeMethod);
      // document.getElementById("fileInput").click();
      // this.closeModal();
      // H5 调用原生方法
      window.nativeMethod.chooseImageFromAlbum();
    },
    // 监听获取相册选择图片信息
    getAlbumImgInfo(e) {
      const _this = this;
      document
        .getElementById("fileInput")
        .addEventListener("change", function (event) {
          console.log("change-本地图片", event);
          const file = event.target.files[0]; // 获取用户选择的文件
          console.log("获取用户选择的文件", file);
          console.log("获取用户选择的文件name", file.name);
          let imageName = file.name;
          let fileType = file.type;
          if (file) {
            const reader = new FileReader(); // 创建FileReader对象
            reader.onload = function (e) {
              console.log("eeeeeeeeeeeee", e);
              let imgUrl = e.target.result; // 获取文件内容的base64编码
              let sizeInKB = (e.total / 1024).toFixed(2) + "KB";
              // const img = document.createElement("img"); // 创建img元素
              // img.src = imgUrl; // 设置img的src属性为读取的文件内容
              // img.style.maxWidth = "100%"; // 设置图片最大宽度为容器宽度
              // img.style.maxHeight = "100%"; // 设置图片最大高度为容器高度

              // const container = document.getElementById("imageContainer");
              // container.innerHTML = ""; // 清空容器内容
              // container.appendChild(img); // 将img元素添加到容器中

              let currentTime = new Date().getTime();
              let imgInfo = {
                key: currentTime, // 唯一标识符
                name: imageName, // 名称
                size: sizeInKB, // 大小
                file: file, // 文件流
                url: imgUrl, // base64码
                createDate: currentTime,
                fileId: currentTime,
                fileSize: e.total,
                fileType: fileType,
                uid: `key_${currentTime}_image`,
              };
              console.log("imgInfo", imgInfo, "列表", _this);
              _this.imglists.push(imgInfo); // 添加到图片列表
            };
            reader.readAsDataURL(file); // 读取文件内容
          }
        });
    },
    // 打开相机弹框
    openCameraModal() {
      let modal = this.cameraModal;
      modal.style.display = "block";
    },
    // 关闭相机弹框
    closeCameraModal() {
      let modal = this.cameraModal;
      modal.style.display = "none";
      this.stopCamera();
    },
    // 打开相机
    openCamera() {
      this.accessCamera();
    },
    // webView
    webViewToImg() {},
    // 访问摄像头
    async accessCamera() {
      console.log("访问摄像头");
      this.videoDom.style.display = "block";
      let mediaDevices = navigator.mediaDevices;
      if (mediaDevices) {
        // 获取摄像头权限
        navigator.mediaDevices
          .getUserMedia({ video: { facingMode: "user" } }) // 使用前置摄像头
          .then((stream) => {
            this.mediaStream = stream;
            this.videoDom.srcObject = stream;
            this.videoDom.play();

            this.videoDom.style.display = "block";
            this.closeModal();
            this.openCameraModal();
          })
          .catch((err) => {
            console.error("无法访问摄像头:", err);
          });
      } else {
        console.error("无法访问摄像头");
      }
    },
    // 关闭摄像头
    stopCamera() {
      // 停止视频流
      if (this.mediaStream) {
        this.mediaStream.getTracks().forEach((track) => track.stop());
        this.videoDom.style.display = "none";
      }
    },
    // 根据时间戳生成图片名称
    generateImageName() {
      const timestamp = new Date().getTime();
      return `image_${timestamp}.png`;
    },

    // 获取图片信息
    getImgInfoToCapture(canvas, imgUrl) {
      console.log("canvas", canvas);
      // 将Canvas内容转换为Blob对象
      canvas.toBlob((blob) => {
        console.log("blob", blob);
        // 设置图片名称
        const imageName = this.generateImageName();

        // 获取图片大小
        const imageSize = blob.size; // 图片大小,单位为字节
        // 将字节换算成千字节
        const sizeInKB = (imageSize / 1024).toFixed(2) + "KB"; // 保留两位小数

        // 这里可以执行其他操作,比如将Blob对象转换为File对象
        const imageFile = new File([blob], imageName, { type: blob.type });

        let imgInfo = {
          key: new Date().getTime(), // 唯一标识符
          name: imageName, // 名称
          size: sizeInKB, // 大小
          file: imageFile, // 文件流
          url: imgUrl, // base64码
        };
        console.log("图片信息:", imgInfo);
        this.imglists.push(imgInfo); // 添加到图片列表
        // 如果需要,可以在这里执行上传或其他操作
      }, "image/png"); // 指定图片格式
    },
    // canvas转换为图片并添加到页面
    canvasToImg(canvas) {
      // 将绘制的canvas转换为图片
      const img = document.createElement("img");
      let imgUrl = canvas.toDataURL("image/png");
      img.src = imgUrl;
      img.style.width = "100%";
      img.style.height = "100%";
      img.style.objectFit = "cover";
      const imglistDom = this.imglistDom;
      const uploaderImgs = this.uploaderImgDom;
      this.currentCaptureImg = imgUrl;

      imglistDom.innerHTML = ""; // 清空所有子元素
      // 将图片添加到页面中
      imglistDom.appendChild(img);
      // uploaderImgs.appendChild(img);
    },
    // 拍照
    capture() {
      const canvas = this.canvasDom;
      const video = this.videoDom;

      // 设置 canvas 尺寸与视频一致
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      const ctx = canvas.getContext("2d");
      // 绘制视频帧
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

      this.canvasToImg(canvas);

      this.isCapture = true;
    },
    // 选择当前拍照图片
    chooseCurrentCapture() {
      this.closeCameraModal();
      this.getImgInfoToCapture(this.canvasDom, this.currentCaptureImg);
      this.isCapture = false;
    },
    // 返回上传页面
    backToUpload() {
      this.closeCameraModal();
    },
    // 重新拍照
    reCapture() {
      this.isCapture = false;
    },
    // 删除图片
    deleteImg(imgList, index) {
      imgList.splice(index, 1);
    },
  },
  created() {
    // 调用实例,未渲染DOM;
    console.log("created");
  },
  mounted() {
    this.init();
    this.closeChooseModal();
  },
};
</script>
<style scoped>
/* 全局样式 */
body {
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: #000;
  color: #fff;
  font-family: Arial, sans-serif;
}
.choose_modal {
  display: none;
  position: fixed;
  z-index: 1;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: rgb(0, 0, 0);
  background-color: rgba(0, 0, 0, 0.4);
}

.choosemodal-content {
  background-color: #fefefe;
  margin: 15% auto;
  padding: 20px;
  border: 1px solid #888;
  width: 80%;
}

.choosemodal-option {
  margin: 10px 0;
  padding: 10px;
  background-color: #f2f3f5;
  text-align: center;
  cursor: pointer;
}

.choosemodal-option:hover {
  background-color: #f2f3f5;
  color: #1989fa;
}
.camera_modal {
  display: none;
  position: fixed;
  z-index: 99;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  overflow: auto;
  background-color: rgb(0, 0, 0);
}
#back-to-upload {
  display: flex;
  align-items: center;
  justify-content: center;

  position: fixed; /* 或者使用 position: absolute; 根据需要选择 */
  left: 8%; /* 水平居中 */
  /* transform: translateX(-50%); */
  bottom: 7vh;
}
#capture-btn {
  display: flex;
  align-items: center;
  justify-content: center;

  position: fixed; /* 或者使用 position: absolute; 根据需要选择 */
  left: 50%; /* 水平居中 */
  transform: translateX(-50%);
  bottom: 6vh;
}
#capture-out {
  border: 2px solid #fff;
  border-radius: 100%;
  cursor: pointer;
  width: 1.85rem;
  height: 1.85rem;
  display: flex;
  justify-content: center;
  align-items: center;
}
#capture-inner {
  background-color: #fff;
  border-radius: 100%;
  cursor: pointer;
  width: 1.65rem;
  height: 1.65rem;
}

/* 视频容器 */
.camera-container {
  position: relative;
  width: 100vw; /* 宽度为屏幕宽度 */
  height: 100vh; /* 高度为 4:3 比例 */
  max-height: 100vh;
  overflow: hidden;
}

/* 视频流 */
#video {
  width: 100%;
  height: 100%;
  object-fit: cover; /* 确保视频填充整个容器 */
}

/* 人像框 */
.frame {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none; /* 防止人像框干扰点击事件 */
}
.upload-box {
  border: 1px solid #dcdee0;
  text-align: center;
  font-size: 16px;
  display: flex;
  justify-content: center;
  padding: 5px 3px;
}
.upload-box-none {
  display: none;
}
.uploader-img {
}
.img-box {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin: 5px 3px;
  padding: 5px;
}
.img-item {
  display: flex;
}
.img-item-img {
  width: 60px;
  height: 60px;
}

.img-item-img-content {
  border-radius: 4px;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.img-info {
  margin: 0 5px;
}
.img-name {
  font-size: 17px;
  margin: 5px 0;
  width: 200px; /* 设置容器的宽度 */
  overflow: hidden; /* 隐藏溢出的内容 */
  white-space: nowrap; /* 防止文本换行 */
  text-overflow: ellipsis; /* 设置文本溢出时显示省略号 */
}
.img-size {
  font-size: 13px;
  color: #b5b8c2;
}
.uploader_img img {
  width: 48px;
  height: 48px;
}
#capture-img {
  width: 100vw;
  height: 85vh;
}
#capture_img_result {
  display: flex;
  justify-content: space-around;
  line-height: 15vh;
}
.uploader_clibtn {
  width: 25px;
  height: 18px;
}
.delete_btn {
  width: 28px;
  height: 28px;
}
.uploader_btn {
  width: 24px;
  height: 24px;
}
.uploader_squarebtn {
  width: 60px;
  height: 60px;
}
.camera_portrait {
  width: 100%;
  height: 100%;
}
.capture_btn_other {
  width: 32px;
  height: 32px;
}
.isnone {
  display: none;
}
</style>
相关推荐
骑着小黑马几秒前
前端程序员自己的知识库,使用NodeJS+LLM搭建一个属于自己的知识库
前端·人工智能
wordbaby3 分钟前
加速 Web 应用:资源压缩详解与 Vite + Nginx 实践指南
前端·nginx·vite
宝耶19 分钟前
HTML:表格数据展示区
前端·html
程序员海军33 分钟前
一键把网站变成吉卜力风格的神器来了
前端·chatgpt
三原34 分钟前
前端微应用-乾坤(qiankun)原理分析-沙箱隔离(js)
前端·架构·前端框架
IT专家-大狗36 分钟前
Edge浏览器安卓版流畅度与广告拦截功能评测【不卡还净】
android·前端·edge
Kx…………1 小时前
Day3:个人中心页面布局前端项目uniapp壁纸实战
前端·学习·uni-app·实战·项目
肠胃炎1 小时前
认识Vue
前端·javascript·vue.js
七月丶1 小时前
🛠 用 Node.js 和 commander 快速搭建一个 CLI 工具骨架(gix 实战)
前端·后端·github
砖吐筷筷1 小时前
我理想的房间是什么样的丨去明日方舟 Only 玩 - 筷筷月报#18
前端·github