1. 程式人生 > 程式設計 >Vue呼叫PC攝像頭實現拍照功能

Vue呼叫PC攝像頭實現拍照功能

本文例項為大家分享了呼叫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,_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({imaghttp://www.cppcns.come: this.imgSrc}) .then(res => { this.$emit('fileUpload',res.retData.imagePath) addUserCard({userId: this.deleteData.userid,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.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,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="Vue呼叫PC攝像頭實現拍照功能">
      <i class="delete-btn" @click="deleteUploadFile" v-if="deleteData.imagePath">x</i>
    </div>
    <div class="upload-btn">
       <input type="file" name="userAuditInwww.cppcns.comfo" id="userAuditInfo" @change="getUploadFile" ref="inputFile">
       <el-button type="defualt" size="small" @click="localUploadF客棧ile">本地上傳</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,addUserCard } from "@/api/houseApi."
  export default {
    data() {
      return {
        filePath: require('@/assets/images/null.png'),//身份證頭像
        dialogVisible: false,//操作刪除人臉照片相關欄位
        deleteData: {
          userid: this.$route.query.userId,id: ``,cardType: 4,www.cppcns.com    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,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>

以上只作為實現參考,具體操作依實際需求做相應調整。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。