Vue调用PC摄像头实现拍照功能

本文实例为大家分享了Vue调用PC摄像头实现拍照功能的具体代码,供大家参考,具体内容如下

项目需求:可以本地上传头像,也可以选择拍摄头像上传。

组件:

1、Camera组件:实现 打开、关闭摄像头、绘制、显示图片、用于上传
2、CameraDialog组件:使用ElementUI dialog组件 展示摄像头UI效果
3、外部调用CameraDialog组件,实现拍摄头像上传功能
4、本地上传可使用原生input、也可使用ElementUI upload组件

操作逻辑:

1、新增时将头像图片转为base64调用接口提交,返回url地址用于前端展示
2、替换时,先执行删除操作,在依新增操作执行。
3、本地上传原理跟拍摄上传一致

具体实现方法:

Camera组件

<template>
  <div class="camera-box">
    <video id="video" :width="videoWidth" :height="videoHeight" v-show="!imgSrc"></video>
    <canvas id="canvas" :width="videoWidth" :height="videoHeight" v-show="imgSrc"></canvas>
    <p class="camera-p">{{!imgSrc?'提示:请将头像居中按"拍照"键确认':''}}</p>
    <el-button type="primary" @click="setImage" v-if="!imgSrc" class="camera-btn">拍照</el-button>
    <el-button type="primary" v-if="imgSrc" @click="setFileUpload" class="camera-btn">上传</el-button>
  </div>
</template>

<script>
  import {setFileUpload, deleteFileUpload, addUserCard } from "@/api/houseApi";

  export default {
    name: 'Camera',
    props: {
      //【必选】CameraDialog弹窗显示状态
      show: {type: Boolean},
      //【可选】配合原生input本地上传,用于替换时执行删除
      deleteData: {type: Object}
    },
    data() {
      return {
        videoWidth: '401',
        videoHeight: '340',
        thisCancas: null,
        thisContext: null,
        thisVideo: null,
        imgSrc: ``,
      }
    },
    mounted() {
      if (this.show) this.getCompetence()
    },
    methods: {
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function  调用权限
       *****************************************/
      getCompetence() {
        var _this = this
        this.thisCancas = document.getElementById('canvas')
        this.thisContext = this.thisCancas.getContext('2d')
        this.thisVideo = document.getElementById('video')
        // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
        if (navigator.mediaDevices === undefined) {
          navigator.mediaDevices = {}
        }
        // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
        // 使用getUserMedia,因为它会覆盖现有的属性。
        // 这里,如果缺少getUserMedia属性,就添加它。
        if (navigator.mediaDevices.getUserMedia === undefined) {
          navigator.mediaDevices.getUserMedia = function (constraints) {
            // 首先获取现存的getUserMedia(如果存在)
            var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia
            // 有些浏览器不支持,会返回错误信息
            // 保持接口一致
            if (!getUserMedia) {
              return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
            }
            // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
            return new Promise(function (resolve, reject) {
              getUserMedia.call(navigator, constraints, resolve, reject)
            })
          }
        }
        var constraints = {
          audio: false,
          video: {width: this.videoWidth, height: this.videoHeight, transform: 'scaleX(-1)'}
        }
        navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
          // 旧的浏览器可能没有srcObject
          if ('srcObject' in _this.thisVideo) {
            _this.thisVideo.srcObject = stream
          } else {
            // 避免在新的浏览器中使用它,因为它正在被弃用。
            _this.thisVideo.src = window.URL.createObjectURL(stream)
          }
          _this.thisVideo.onloadedmetadata = function (e) {
            _this.thisVideo.play()
          }
        }).catch(err => {
          console.log(err)
        })
      },
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function  绘制图片
       *****************************************/
      setImage() {
        var _this = this
        // 点击,canvas画图
        _this.thisContext.drawImage(_this.thisVideo, 0, 0, _this.videoWidth, _this.videoHeight)
        // 获取图片base64链接
        var image = this.thisCancas.toDataURL('image/png')
        _this.imgSrc = image
        // console.log(_this.imgSrc)
        // this.$emit('refreshDataList', this.imgSrc)
      },
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function  base64转文件
       *****************************************/
      dataURLtoFile(dataurl, filename) {
        var arr = dataurl.split(',')
        var mime = arr[0].match(/:(.*?);/)[1]
        var bstr = atob(arr[1])
        var n = bstr.length
        var u8arr = new Uint8Array(n)
        while (n--) {
          u8arr[n] = bstr.charCodeAt(n)
        }
        return new File([u8arr], filename, {type: mime})
      },
      /*
       *@author Brady
       *@Time 2019/9/5
       *@function  关闭摄像头
       *****************************************/
      stopNavigator() {
        this.thisVideo.srcObject.getTracks()[0].stop()
      },
      //上传图片
      setFileUpload() {
        //编辑档案-上传人脸照片
        if(this.deleteData) {
          if (this.deleteData.imagePath) {
            deleteFileUpload({id: this.deleteData.id, filePath: this.deleteData.imagePath})
              .then(res => {
                setFileUpload({image: this.imgSrc})
                  .then(res => {
                    this.$emit('fileUpload', res.retData.filePath, res.retData.imagePath)
                    addUserCard({userId: this.deleteData.userid, cardType: this.deleteData.cardType, userAuditInfo: res.retData.imagePath})
                      .then(res => {
                        this.$message({message: "上传成功", type: "success"})
                      })
                      .catch(err => {
                        console.log(err)
                      })
                  })
                  .catch(err => {
                    console.log(err)
                  })
              })
              .catch(err => {
                console.log(err)
              })
          } else {
            setFileUpload({image: this.imgSrc})
              .then(res => {
                this.$emit('fileUpload', res.retData.filePath, res.retData.imagePath)
                addUserCard({userId: this.deleteData.userid, cardType: this.deleteData.cardType, userAuditInfo: res.retData.imagePath})
                  .then(res => {
                    this.$message({message: "上传成功", type: "success"})
                  })
                  .catch(err => {
                    console.log(err)
                  })
              })
              .catch(err => {
                console.log(err)
              })
          }
        } else {
          //添加住户-上传人脸照片
          setFileUpload({image: this.imgSrc})
            .then(res => {
              // console.log(res)
              this.$message({message: "上传成功", type: "success"})
              this.$emit('fileUpload', res.retData.filePath, res.retData.imagePath)
            })
            .catch(err => {
              console.log(err)
            })
        }
      },
    },
    watch: {
      show(val) {
        if (val) {
          this.imgSrc = ``
          this.getCompetence()
        } else {
          this.stopNavigator()
        }
      },
    }
  }
</script>

<style lang="less">
  .camera-box {
    margin: 0 auto;
    text-align: center;

    .camera-p {
      height: 17px;
      line-height: 17px;
      font-size: 12px;
      font-family: "PingFang SC";
      font-weight: 400;
      color: rgba(154, 154, 154, 1);
      text-align: left;
    }

    .camera-btn {
      margin-top: 20px;
    }

  }
</style>

CameraDialog组件

<template>
  <div id="camera-dialog">
    <el-dialog
            title="拍摄照片"
            :visible.sync="dialogVisible"
            top="5vh"
            width="481px"
            @close="dialogCancle"
            :close-on-click-modal="false"
            :before-close="dialogCancle"
    >
      <Camera :show="dialogVisible" :deleteData="deleteData" @fileUpload="fileUpload"></Camera>
      <span slot="footer" class="dialog-footer">
          <!-- <el-button @click="dialogCancle">取 消</el-button> -->
        <!-- <el-button type="primary">确 定</el-button> -->
        </span>
    </el-dialog>
  </div>
</template>

<script>
  import Camera from "@/page/house/Camera.vue"

  export default {
    name: 'CameraDialog',
    props: {
      dialogVisible: {type: Boolean},
      deleteData: {type: Object}
    },
    components: {
      Camera
    },
    data() {
      return {
        filePath: ``,
        imagePath: ``,
      }
    },
    methods: {
      //关闭弹窗
      dialogCancle() {
        this.$emit('dialogCancle', false, this.filePath, this.imagePath);
      },
      //获取人脸照片地址
      fileUpload(filePath, imagePath) {
        this.filePath = filePath
        this.imagePath = imagePath
        this.dialogCancle()
      }
    }
  }
</script>

<style scoped>
</style>

外部调用组件

<template>
  <div>
    <div class="form-thumb">
     <img :src="filePath" alt="">
      <i class="delete-btn" @click="deleteUploadFile" v-if="deleteData.imagePath">x</i>
    </div>
    <div class="upload-btn">
       <input type="file" name="userAuditInfo" id="userAuditInfo" @change="getUploadFile" ref="inputFile">
       <el-button type="defualt" size="small" @click="localUploadFile">本地上传</el-button>
       <el-button type="default" size="small" @click="dialogVisible=true">拍摄照片</el-button>
     </div>
    <!-- 拍摄照片弹窗 -->
    <CameraDialog :dialogVisible="dialogVisible" @dialogCancle="dialogCancleCamera" :deleteData="deleteData" />
  </div>
</template>

<script>
  import CameraDialog from "./CameraDialog.vue"
  import { setFileUpload, deleteFileUpload, addUserCard } from "@/api/houseApi.js"
  export default {
    data() {
      return {
        filePath: require('@/assets/images/null.png'), //身份证头像
        dialogVisible: false,
        //操作删除人脸照片相关字段
        deleteData: {
          userid: this.$route.query.userId,
          id: ``,
          cardType: 4,
          imagePath: ``,
        }
   }
 },
 methods: {
      //模拟点击本地上传人脸照片
      localUploadFile() {
        this.$refs.inputFile.click()
      },
      //本地上传人脸照片
      getUploadFile() {
        let input = document.getElementById('userAuditInfo')
        let file = input.files[0]
        this.getBase64(file)
          .then(res => {
            if (this.deleteData.imagePath) {
              deleteFileUpload({id: this.deleteData.id, filePath: this.deleteData.imagePath})
                .then(() => {
                  this.setFileUpload(res)
                })
            } else {
              this.setFileUpload(res)
            }
          })
          .catch(err => {
            console.log(err)
          })
      },
      //上传人脸照片
      setFileUpload(res) {
        setFileUpload({image: res})
          .then(res => {
            this.filePath = res.retData.filePath
            this.deleteData.imagePath = res.retData.imagePath
            addUserCard({userId: this.deleteData.userid, cardType: this.deleteData.cardType, userAuditInfo: res.retData.imagePath})
              .then(res => {
                this.$message({message: res.retInfo, type: "success"})
                //用于更新数据,此方法未展示
                this.getInfo()
              })
              .catch(err => {
                console.log(err)
              })
          })
          .catch(err => {
            console.log(err)
          })
      },
      //转base64
      getBase64(file) {
        return new Promise(function (resolve, reject) {
          let reader = new FileReader();
          let imgResult = "";
          reader.readAsDataURL(file);
          reader.onload = function () {
            imgResult = reader.result;
          };
          reader.onerror = function (error) {
            reject(error);
          };
          reader.onloadend = function () {
            resolve(imgResult);
          };
        });
      },
      //删除人脸照片
      deleteUploadFile() {
        this.$confirm(`确认删除?`, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          deleteFileUpload({id: this.deleteData.id, filePath: this.deleteData.imagePath})
            .then(res => {
              this.$message({message: res.retInfo, type: "success"})
              this.filePath = require('@/assets/images/null.png')
              this.deleteData.imagePath = ''
            })
            .catch(err => {
              console.log(err)
            })
        }).catch(() => {});
      },
      //Dialog弹窗取消、获取上传人脸照片
      dialogCancleCamera(str, filePath, imagePath) {
        this.dialogVisible = str
        // this.houseInfo.filePath = filePath
        // this.houseInfo.userAuditInfo = imagePath
        this.filePath = filePath
        this.deleteData.imagePath = imagePath
        this.getInfo()
      },
 }
  }
</script> 

<style scoped="scoped">
  .upload-btn {
    position: relative;
    margin: 20px 12px 0 0;
    text-align: right;
  }
  input#userAuditInfo {
    position: absolute;
    display: inline-block;
    width: 80px;
    height: 32px;
    top: 0;
    cursor: pointer;
    font-size: 0;
    z-index: -1;
    /*opacity: 0;*/
  }
  .delete-btn {
    position: absolute;
    top: -6px;
    right: -6px;
    display: inline-block;
    width: 16px;
    height: 16px;
    line-height: 14px;
    background: rgba(251, 135, 66, 1);
    border-radius: 8px;
    text-align: center;
    font-size: 12px;
    color: #fff;
    cursor: pointer;
  }
</style>

以上只作为实现参考,具体操作依实际需求做相应调整。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • vue2实现移动端上传、预览、压缩图片解决拍照旋转问题

    因为最近遇到个移动端上传头像的需求,上传到后台的数据是base64位,其中为了提高用户体验,把比较大的图片用canvas进行压缩之后再进行上传.在移动端调用拍照功能时,会发生图片旋转,为了解决这个问题引入了exif去判断拍照时的信息再去处理图片,这是个很好的插件.关于exif.js可以去他的GitHub上了解,这边直接 npm install exif-js --save   安装,然后import一下就可以使用了.以下就是源码,可以直接使用. <template> <div> &

  • Vue.js 2.0 移动端拍照压缩图片预览及上传实例

    在学习和使用Vue.js 2.0 的过程中遇到不少不一样的地方,本来移动端开发H5应用,准备将mui框架和Vue.js+vue-router+vuex 全家桶结合起来使用,但是在拍照上传的实现过程中遇到了无法调用plus的H5+接口的问题,所以最后拍照上传功能还是使用input file方式里解决的.但是内心还是不甘心的,由于项目进度推进,迭代版本,所以不得不放弃,后续可能我将此功能使用调用H5+接口实现. 首先我来讲我实现这个拍照预览压缩上传的思路,准确的说应该是拍照或选择图片压缩之后预览及上

  • Vue2.0实现调用摄像头进行拍照功能 exif.js实现图片上传功能

    本文实例为大家分享了Vue2.0实现调用摄像头进行拍照功能的具体代码,以及图片上传功能引用exif.js,供大家参考,具体内容如下 可以在github 上下载demo链接 vue组件代码 <template> <div> <div style="padding:20px;"> <div class="show"> <div class="picture" :style="'backg

  • vue调用本地摄像头实现拍照功能

    前言: vue调用本地摄像头实现拍照功能,由于调用摄像头有使用权限,只能在本地运行,线上需用https域名才可以使用.实现效果: 1.摄像头效果: 2.拍照效果: 实现代码: <template> <div class="camera_outer"> <video id="videoCamera" :width="videoWidth" :height="videoHeight" autoplay

  • Vue.js 2.0 移动端拍照压缩图片上传预览功能

    在学习和使用Vue.js 2.0 的过程中遇到不少不一样的地方,本来移动端开发H5应用,准备将mui框架和Vue.js+vue-router+vuex 全家桶结合起来使用,但是在拍照上传的实现过程中遇到了无法调用plus的H5+接口的问题,所以最后拍照上传功能还是使用input file方式里解决的.但是内心还是不甘心的,由于项目进度推进,迭代版本,所以不得不放弃,后续可能我将此功能使用调用H5+接口实现. 首先我来讲我实现这个拍照预览压缩上传的思路,准确的说应该是拍照或选择图片压缩之后预览及上

  • vuejs开发组件分享之H5图片上传、压缩及拍照旋转的问题处理

    一.前言 三年.net开发转前端已经四个月了,前端主要用webpack+vue,由于后端转过来的,前端不够系统,希望分享下开发心得与园友一起学习. 图片的上传之前都是用的插件(ajaxupload),或者传统上传图片的方式,各有利弊:插件的问题是依赖jq并且会使系统比较臃肿,还有传统的web开发模式 前后端偶尔在一起及对用户体验要求低,现在公司采用webpack+vue+restfullApi开发模式 前后端完全分离,遵从高内聚,低偶尔的原则,开发人员各司其职,一则提升开发效率(从长期来看,短期

  • vue实现pc端拍照上传功能

    本文实例为大家分享了vue实现pc端拍照上传功能的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html> <head> <meta charset="UTF8"> </head> <body> <div id="contentHolder"> <video id="video" width="320" heigh

  • vue调取电脑摄像头实现拍照功能

    本文实例为大家分享了vue调取电脑摄像头实现拍照功能的具体代码,供大家参考,具体内容如下 实现效果图: 拍照前&拍照后(我电脑摄像头挡住的,所以图片是灰色) 1.点击拍照上传功能调取电脑摄像头权限 2.选择允许使用摄像头之后,页面摄像头区域开始显示画面 3.点击拍照按钮,右侧显示拍摄的图片.点击保存即可 完整代码: 我这里写的是一个组件,所以触发调取摄像头事件是从父组件传过来的.也可以直接写一个页面上. <template> <div class="camera-box

  • Vue调用PC摄像头实现拍照功能

    本文实例为大家分享了Vue调用PC摄像头实现拍照功能的具体代码,供大家参考,具体内容如下 项目需求:可以本地上传头像,也可以选择拍摄头像上传. 组件: 1.Camera组件:实现 打开.关闭摄像头.绘制.显示图片.用于上传 2.CameraDialog组件:使用ElementUI dialog组件 展示摄像头UI效果 3.外部调用CameraDialog组件,实现拍摄头像上传功能 4.本地上传可使用原生input.也可使用ElementUI upload组件 操作逻辑: 1.新增时将头像图片转为

  • C#调用摄像头实现拍照功能的示例代码

    前言 老师要求我们学生做一套拍照身份验证系统,经过长时间的学习,有了这篇文章,希望能帮到读者们. 正文 首先介绍本文的主角:AForge 创建一个C#项目,引用必备的几个DLL AForge.dll AForge.Controls.dll AForge.Imaging.dll AForge.Math.dll AForge.Video.DirectShow.dll AForge.Video.dll 这些DLL读者们可以在文末下载我附带的Demon 引用必要的命名空间 using AForge.Co

  • Java+OpenCV调用摄像头实现拍照功能

    目录 环境准备 制作主界面 整体结构介绍 核心代码与知识点讲解 JPanel中如何显示摄像头的图像 OpenCV调用摄像头 使用摄像头拍照 完整代码 OpenCVUtil.java ImageUtils.java FileBean.java VideoPanel.java TakePhotoProcess.java FaceRecognize.java(核心主类) 随着我们对环境.Mat基本使用越来越熟练.Java Swing也逐步熟悉了起来.今天我们开始进入OpenCV驱动摄像头的几个使用场景

  • Android实现调用摄像头进行拍照功能

    现在Android智能手机的像素都会提供照相的功能,大部分的手机的摄像头的像素都在1000万以上的像素,有的甚至会更高.它们大多都会支持光学变焦.曝光以及快门等等. 下面的程序Demo实例示范了使用Camera v2来进行拍照,当用户按下拍照键时,该应用会自动对焦,当对焦成功时拍下照片. layout/activity_main.xml界面布局代码如下: <?xml version="1.0" encoding="utf-8"?> <manifes

  • 微信小程序调用摄像头实现拍照功能

    本文实例为大家分享了微信小程序调用摄像头实现拍照的具体代码,供大家参考,具体内容如下 微信小程序开发文档 首先,需要用户授权摄像头权限,这一步是必须的 具体步骤: 1.获取用户当前授权状态,看是否已经授权,如果已经授权直接显示摄像头2.如果用户还没有授权,则调起授权弹框,用户允许授权则显示摄像头3.如果用户不允许,则提示用户去设置页面打开摄像头权限 用户授权之后,就可以进行拍摄了,微信的camera组件无法显示为圆形,我这里是用一张图片遮盖了 上代码: wxml: <view class='ca

  • Electron调用外接摄像头并拍照上传实现详解

    目录 背景 需求分析 实现 视频采集 MediaDevices.getUserMedia() 拍照生成图片 上传图片至CDN 1. 使用HTMLCanvasElement.toBlob() 语法 参数 2. 使用HTMLCanvasElement.toDataURL() 语法 参数 返回值 总结 背景 基于Electron实现的pc端智能验机应用,近期迭代了一个新的功能,需求是通过电脑外接摄像头对手机屏幕进行拍照,拍照后需将照片上传至服务端进行屏幕信息比对,确定被检测屏幕是否为原厂屏. 需求分析

  • Android实现摄像头拍照功能

    应用场景: 在Android开发过程中,有时需要调用手机自身设备的功能,本文侧重摄像头拍照功能的调用. 知识点介绍: 使用权限:调用手机自身设备功能(摄像头拍照功能),应该确保已经在AndroidManifest.xml中正确声明了对摄像头的使用及其它相关的feature. <!--摄像头权限 --> <uses-permission android:name="android.permission.CAMERA" /> <!--存储权限 SD卡读写权限

  • Android调用系统摄像头拍照并显示在ImageView上

    简介 现在市面上的apk只要涉及用户中心都会有头像,而且这个头像也是可自定义的,有的会采取读取相册选择其中一张作为需求照片,另一种就是调用系统摄像头拍照并获取即时照片,本博文就是讲述如何调用摄像头拍照并显示在指定的控件上. 先来看看效果图 由于这里我用的是模拟器没有摄像头,所以拍照是黑的,至于里面2个红色圆圈那是Genymotion自带的标志. 实现起来比较简单: activity_main.xml <?xml version="1.0" encoding="utf-8

随机推荐