Vue調(diào)用PC攝像頭實(shí)現(xiàn)拍照功能
本文實(shí)例為大家分享了Vue調(diào)用PC攝像頭實(shí)現(xiàn)拍照功能的具體代碼,供大家參考,具體內(nèi)容如下
項(xiàng)目需求:可以本地上傳頭像,也可以選擇拍攝頭像上傳。
組件:
1、Camera組件:實(shí)現(xiàn) 打開、關(guān)閉攝像頭、繪制、顯示圖片、用于上傳
2、CameraDialog組件:使用ElementUI dialog組件 展示攝像頭UI效果
3、外部調(diào)用CameraDialog組件,實(shí)現(xiàn)拍攝頭像上傳功能
4、本地上傳可使用原生input、也可使用ElementUI upload組件
操作邏輯:
1、新增時將頭像圖片轉(zhuǎn)為base64調(diào)用接口提交,返回url地址用于前端展示
2、替換時,先執(zhí)行刪除操作,在依新增操作執(zhí)行。
3、本地上傳原理跟拍攝上傳一致
具體實(shí)現(xiàn)方法:
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?'提示:請將頭像居中按"拍照"鍵確認(rèn)':''}}</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彈窗顯示狀態(tài) show: {type: Boolean}, //【可選】配合原生input本地上傳,用于替換時執(zhí)行刪除 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 調(diào)用權(quán)限 *****************************************/ getCompetence() { var _this = this this.thisCancas = document.getElementById('canvas') this.thisContext = this.thisCancas.getContext('2d') this.thisVideo = document.getElementById('video') // 舊版本瀏覽器可能根本不支持mediaDevices,我們首先設(shè)置一個空對象 if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {} } // 一些瀏覽器實(shí)現(xiàn)了部分mediaDevices,我們不能只分配一個對象 // 使用getUserMedia,因?yàn)樗鼤采w現(xiàn)有的屬性。 // 這里,如果缺少getUserMedia屬性,就添加它。 if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = function (constraints) { // 首先獲取現(xiàn)存的getUserMedia(如果存在) var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia // 有些瀏覽器不支持,會返回錯誤信息 // 保持接口一致 if (!getUserMedia) { return Promise.reject(new Error('getUserMedia is not implemented in this browser')) } // 否則,使用Promise將調(diào)用包裝到舊的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 { // 避免在新的瀏覽器中使用它,因?yàn)樗诒粭売谩? _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 // 點(diǎn)擊,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轉(zhuǎn)文件 *****************************************/ 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 關(guān)閉攝像頭 *****************************************/ 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: { //關(guān)閉彈窗 dialogCancle() { this.$emit('dialogCancle', false, this.filePath, this.imagePath); }, //獲取人臉照片地址 fileUpload(filePath, imagePath) { this.filePath = filePath this.imagePath = imagePath this.dialogCancle() } } } </script> <style scoped> </style>
外部調(diào)用組件
<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, //操作刪除人臉照片相關(guān)字段 deleteData: { userid: this.$route.query.userId, id: ``, cardType: 4, imagePath: ``, } } }, methods: { //模擬點(diǎn)擊本地上傳人臉照片 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"}) //用于更新數(shù)據(jù),此方法未展示 this.getInfo() }) .catch(err => { console.log(err) }) }) .catch(err => { console.log(err) }) }, //轉(zhuǎn)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(`確認(rèn)刪除?`, '提示', { 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>
以上只作為實(shí)現(xiàn)參考,具體操作依實(shí)際需求做相應(yīng)調(diào)整。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- vue3開啟攝像頭并進(jìn)行拍照的實(shí)現(xiàn)示例
- vue如何調(diào)用攝像頭實(shí)現(xiàn)拍照上傳圖片、本地上傳圖片
- vue調(diào)用攝像頭進(jìn)行拍照并能保存到本地的方法
- Vue實(shí)現(xiàn)調(diào)用PC端攝像頭實(shí)時拍照
- vue調(diào)取電腦攝像頭實(shí)現(xiàn)拍照功能
- vue調(diào)用本地攝像頭實(shí)現(xiàn)拍照功能
- Vue2.0實(shí)現(xiàn)調(diào)用攝像頭進(jìn)行拍照功能 exif.js實(shí)現(xiàn)圖片上傳功能
- vue 獲取攝像頭拍照并旋轉(zhuǎn)、裁剪生成新的圖片功能實(shí)現(xiàn)
相關(guān)文章
手把手教你Vue3實(shí)現(xiàn)路由跳轉(zhuǎn)
Vue Router是Vue.js的官方路由器,它與Vue.js核心深度集成,使使用Vue.js構(gòu)建單頁應(yīng)用程序變得輕而易舉,下面這篇文章主要給大家介紹了關(guān)于Vue3實(shí)現(xiàn)路由跳轉(zhuǎn)的相關(guān)資料,需要的朋友可以參考下2022-08-08vue指令只能輸入正數(shù)并且只能輸入一個小數(shù)點(diǎn)的方法
這篇文章主要介紹了vue指令只能輸入正數(shù)并且只能輸入一個小數(shù)點(diǎn)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06Vuex數(shù)據(jù)持久化的兩種方式:手動存儲和vuex-persistedstate插件詳解
這篇文章主要介紹了Vuex數(shù)據(jù)持久化的兩種方式:手動存儲和vuex-persistedstate插件,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08vue設(shè)置導(dǎo)航欄、側(cè)邊欄為公共頁面的例子
今天小編就為大家分享一篇vue設(shè)置導(dǎo)航欄、側(cè)邊欄為公共頁面的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11vue-cli3 打包優(yōu)化之 splitchunks詳解
這篇文章主要介紹了vue-cli3 打包優(yōu)化之 splitchunks的相關(guān)知識,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07