VUE 调用PC摄像头,HTTP下也可以使用
生活随笔
收集整理的這篇文章主要介紹了
VUE 调用PC摄像头,HTTP下也可以使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
由于內網使用,調用當前pc的攝像頭,進行拍照上傳功能,而瀏覽器由于安全策略考慮,只支持本地調用攝像頭,服務器上禁止使用,新版chrome支持修改安全協議,代碼如下:
chrome://flags/#unsafely-treat-insecure-origin-as-secure然后,將該 flag 切換成 enable 狀態;
在輸入框中填寫需要開啟的域名或地址例:http://xxx.xxx.xx.xx:1234,如果有多個,則以逗號分隔;
重啟瀏覽器后生效;
下面寫了個子組件photo.vue,來調用,可以上傳多張照片,通過elemenui支持查看
<template><div><el-dialog v-el-drag-dialog width="720px" :title="title" :close-on-click-modal="false" :visible.sync="dialogPhotoVisible"><div v-show="!noShow" class="pictureBox"><div><div v-show="cameraShow" id="my_camera"><video id="videoCamera" :width="videoWidth" :height="videoHeight" autoplay></video><canvas style="display:none;" id="canvasCamera" :width="videoWidth" :height="videoHeight"></canvas></div><div v-show="!cameraShow" class="camera_no"><div><i class="el-icon-loading"/></div><div class="text">{{ loadingText }}</div></div></div><div class="picList"><div v-for="(s, index) in listSrc" style="position: relative"><el-imagestyle="width: 100%; height: 130px":src="s.src":preview-src-list="getSrcList(index)" lazy></el-image><i class="el-icon-error" @click="delClick(s)"></i></div></div></div><div v-show="noShow" class="camera_no_data"><div><i class="el-icon-loading"/></div><div class="text">{{ loadingErrorText }}</div></div><div class="btn-group" v-show="!noShow"><div class="btn-cn" v-show="cameraShow"><el-button type="warning" :loading="saveLoading" @click="takeSnapShot()">拍照</el-button><el-button v-if="listSrc.length !== 0" type="danger" :loading="saveLoading" @click="againTakePhoto()">清空</el-button><el-button type="primary" :loading="saveLoading" @click="saveSnapShot()">上傳</el-button></div></div><div slot="footer" class="dialog-footer"><el-button @click="dialogPhotoVisible = false">關 閉</el-button></div></el-dialog></div> </template> <script>import { dataToFile } from '@/utils/index'import { uploadApplyFiles } from '@/api/common'export default {name: 'PhotoApply',data() {return {dialogPhotoVisible: false,videoWidth: 480,videoHeight: 360,imgSrc: "",thisCancas: null,thisContext: null,thisVideo: null,stream: null,src: '',listSrc: [],takePhoto: true,cameraShow: false,saveLoading: false,noShow: false,loadingText: '正在加載攝像頭...',loadingErrorText: '正在加載攝像頭...'}},props: {title: {type: String}},watch: {dialogPhotoVisible(val) {if (val) {this.$nextTick(() => {this.open()})} else {this.listSrc = []this.close()}}},beforeDestroy() {this.listSrc = []},mounted() {},methods: {getSrcList(index){const srcs = this.listSrc.map((v) => { return v.src })return srcs.slice(index).concat(srcs.slice(0,index))},takeSnapShot() {const _this = thisconst timestamp = new Date().getTime()const fileName = _this.applyID + '_' + timestamp// canvas畫圖_this.thisContext.drawImage(_this.thisVideo,0,0,_this.videoWidth,_this.videoHeight);// 獲取圖片base64鏈接const image = _this.thisCancas.toDataURL("image/jpeg");_this.src = image_this.listSrc.push({src: _this.src,file: dataToFile(_this.src, fileName),title: fileName})_this.takePhoto = false},delClick(src) {this.listSrc = this.listSrc.filter((v) => {return src.src !== v.src})},againTakePhoto() {this.src = ''this.listSrc = []},saveSnapShot() {if (this.listSrc.length === 0) {this.$message.warning('請上傳相關數據')return}// 拍照const _this = this// 調用后臺接口_this.saveLoading = true_this.loadingText = '正在上傳圖片,請稍后...'let formData = new FormData()_this.listSrc.forEach((v) => {formData.append("images", v.file)})// 上傳自己可以自己寫uploadApplyFiles(formData).then(res => {// const data = res.message_this.$message.success('上傳圖片成功')_this.dialogPhotoVisible = false}).catch(() => {setTimeout(() => {// 失敗_this.src = ''_this.saveLoading = false_this.takePhoto = true_this.cameraShow = true}, 500)})},close() {this.src = ''this.listSrc = []this.saveLoading = falsethis.cameraShow = falsethis.takePhoto = truethis.loadingText = '正在關閉攝像頭...'this.stopNavigator()},open() {this.cameraShow = falsethis.loadingText = '正在打開攝像頭...'this.getCompetence()setTimeout(() => {this.cameraShow = true}, 1500)},// 調用權限(打開攝像頭功能)getCompetence() {const _this = this;_this.thisCancas = document.getElementById("canvasCamera");_this.thisContext = this.thisCancas.getContext("2d");_this.thisVideo = document.getElementById("videoCamera");_this.thisVideo.style.display = 'block';// 獲取媒體屬性,舊版本瀏覽器可能不支持mediaDevices,我們首先設置一個空對象if (navigator.mediaDevices === undefined) {navigator.mediaDevices = {};}// 一些瀏覽器實現了部分mediaDevices,我們不能只分配一個對象// 使用getUserMedia,因為它會覆蓋現有的屬性。// 這里,如果缺少getUserMedia屬性,就添加它。if (navigator.mediaDevices.getUserMedia === undefined) {navigator.mediaDevices.getUserMedia = function(constraints) {// 首先獲取現存的getUserMedia(如果存在)const getUserMedia =navigator.webkitGetUserMedia ||navigator.mozGetUserMedia ||navigator.getUserMedia;// 有些瀏覽器不支持,會返回錯誤信息// 保持接口一致if (!getUserMedia) {//不存在則報錯return Promise.reject(_this.$message.error("瀏覽器沒有打開攝像頭的權限!"));}// 否則,使用Promise將調用包裝到舊的navigator.getUserMediareturn new Promise(function(resolve, reject) {getUserMedia.call(navigator, constraints, resolve, reject);});};}let constraints = {audio: false,video: {width: this.videoWidth,height: this.videoHeight,transform: "scaleX(-1)"}};navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {_this.stream = stream// 舊的瀏覽器可能沒有srcObjectif ("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);this.$nextTick(() => {this.noShow = truethis.loadingErrorText = '瀏覽器沒有打開攝像頭的權限!在chrome瀏覽器的地址欄中輸入: chrome://flags/#unsafely-treat-insecure-origin-as-secure,將該 flag 切換成 enable 狀態;\n' +'在輸入框中填寫需要開啟的域名或地址,如果有多個,則以逗號分隔;\n' +'重啟瀏覽器后生效。'})});},// 關閉攝像頭stopNavigator() {if (this.stream) {if (this.stream.getVideoTracks) {let tracks = this.stream.getVideoTracks();if (tracks && tracks[0] && tracks[0].stop) tracks[0].stop();} else if (this.stream.stop) {this.stream.stop();}}}}} </script><style scoped lang="scss">.pictureBox {display: flex;align-items: center;justify-content: space-between;}.btn-cn {width: 100%;text-align: center;margin-top: 20px;margin-bottom: 20px;}#my_camera {border: 1px solid #606266;}.picList{width: 200px;overflow-x: hidden;overflow-y: scroll;height: 360px;.el-image{width: 180px;height: 130px;margin: 0px 0px 10px 10px;}}.camera_no_data{display: flex;flex-direction: column;justify-content: center;align-items: center;padding: 50px;width: 100%;margin-bottom: 20px;background: #fff;height: 360px;border: 1px solid #606266;.el-icon-loading {font-size: 40px;}.text {font-size: 20px;margin-top: 30px;}}.camera_no {position: relative;background: #fff;width: 480px;height: 360px;border: 1px solid #606266;display: flex;flex-direction: column;justify-content: center;align-items: center;.el-icon-loading {font-size: 40px;}.text {font-size: 20px;margin-top: 30px;}}::v-deep .el-image-viewer__mask {opacity: .9;background: #fff;}.el-icon-error{position: absolute;right: 0;top: 0;font-size: 25px;color: yellow;cursor: pointer;} </style>dataToFile.js
/*** 將base64轉換成file*/ export function dataToFile(base64, fileName){const parts = base64.split(';base64,')const contentType = parts[0].split(':')[1]const raw = window.atob(parts[1])const rawLength = raw.lengthconst uInt8Array = new Uint8Array(rawLength)for (let i = 0; i < rawLength; ++i) {uInt8Array[i] = raw.charCodeAt(i)}return new File([uInt8Array], fileName, {type: contentType, lastModified: Date.now()}) }父組件里調用
<photo red="photo" :title="'圖片拍照上傳'" />import photo from '......../photo.vue'components:{photo },methods: {openClick() {this.$refs['photo'].dialogPhotoVisible = true}}根據網上的博客來封裝了一下,由于關閉不了攝像頭,自己給改裝了一下
原文:
https://blog.csdn.net/RussW0/article/details/104694368/
總結
以上是生活随笔為你收集整理的VUE 调用PC摄像头,HTTP下也可以使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iMacros 常用命令
- 下一篇: VUE 调用PC摄像头,亲测可用