前言
使用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>