Vue呼叫PC攝像頭實現拍照功能
阿新 • • 發佈:2021-09-30
本文例項為大家分享了呼叫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>
以上只作為實現參考,具體操作依實際需求做相應調整。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。