背景
来了来了,用户奇怪的需求又来了,是这样的,原生的文件上传,在移动设备上是可以调用摄像头现拍然后直接上传的,而web端则是弹出选择图片的窗口,而用户用的那个平板,却是后者,他想直接拍直接上传,然后我就想,把设备的照相机功能放在任务栏不就行了吗,结果他们说,操作的工人都是年龄比较大的老工人了,那么繁琐的操作他们整不明白…然后我就只能,封装个组件…
ps:需要注意的是,浏览器只支持 https,localhost和127.0.0.1调用摄像头,而http是不支持的,但是只有http怎么办呢,也是有方法可以配置的:
在浏览器地址栏中输入“chrome://flags/#unsafely-treat-insecure-origin-as-secure”,回车,如下图,将该选项置为Enabled,在输入框中输入需要访问的地址,多个地址使用“,”隔开,然后点击右下角弹出的Relaunch按钮,自动重启浏览器之后就可以在添加的http地址下调用摄像头和麦克风了。
话不多说,上代码:
HTML
<div class="cameraBox"></div>
JS( 这个项目用的jquey,很久没写了,写的不好,大佬勿喷)
var canvas
var video
var videoWidth
var videoHeight
var cameraIsOpen = false // 摄像头是否开启 默认为否
$(()=>{//这里就是一个按钮一个弹框,可以自由发挥let cameraBoxCode = `<button type="button" class="btn btn-default" title="开启摄像头" οnclick="cameraOpen()" ><i class="fa fa-camera"></i></button><span id="photoName"></span><div id='cameraModal' class="modal fade" role="dialog" tabindex="1" aria-hidden="true"><div class="modal-dialog"><div class="modal-content"><div class="modal-header myDataTableModalHead" style="height: 3em;vertical-align: middle;padding: 5px 16px;"><button type="button" class="close" οnclick="modalClose()" aria-label="Close"><span aria-hidden="true">×</span></button><span class="cardIcon"></span><h4 class="modal-title">拍照</h4></div><div class="modal-body" style="max-height:80vh;overflow:overlay"><video id="video" width="100%" autoplay="autoplay"></video><canvas id="canvas" width="100%"></canvas></div><div class="modal-footer"><button type="button" class="btn btn-default" οnclick="modalClose()"><label data-locale="i18n_cancel"></label></button><button type="button" class="btn btn-primary" οnclick="takePhoto()"><label>拍照</label></button></div></div></div></div>`$('.cameraBox').append(cameraBoxCode)
})//打开摄像头弹框
function cameraOpen(){canvas = document.getElementById('canvas')video = document.getElementById('video')$('#cameraModal').modal('show')setTimeout(()=>{getMedia()},1000)
}//调取摄像头
function getMedia(){$('#canvas').hide()$('#video').show()videoWidth = '500'videoHeight = '500' // 摄像头宽高navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMeddia || navigator.msGetUserMedia || navigator.mediaDevices.getUserMediaif (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {navigator.mediaDevices.getUserMedia({video: {width:videoWidth,height:videoHeight},audio: false}).then((stream) => {mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0]video.srcObject =streamvideo.play()cameraIsOpen = true}).catch((err) => {$.modal.error('调用摄像头失败,请检查设备是否连接!')})} else if (navigator.getMedia) {// 使用旧方法打开摄像头navigator.getMedia({video: {width:videoWidth,height:videoHeight},}, (stream) => {mediaStreamTrack = stream.getTracks()[0]video.srcObject =streamvideo.play()cameraIsOpen = true}, (err) => {$.modal.error('调用摄像头失败,请检查设备是否连接!')})}
}//拍照
function takePhoto(){$('#canvas').attr('width',videoWidth)$('#canvas').attr('height',videoHeight)$('#video').hide()$('#canvas').show()let ctx = canvas.getContext('2d')ctx.drawImage(video,0,0,videoWidth,videoHeight)let pic = canvas.toDataURL('image/png')pic = pic.replace(/^data:image\/(png|jpg);base64,/,"")let photo = dataURLtoFile(pic,createPic()) //转文件流$('#photoName').text(photo.name)modalClose()console.log(photo)
}//产生随机图片名称
function createPic(){var now = new Date() var year = now.getFullYear() //得到年份var month = now.getMonth()//得到月份var date = now.getDate()//得到日期var hour = now.getHours()//得到小时var minu = now.getMinutes()//得到分钟month = month + 1if (month < 10) month = '0' + monthif (date < 10) date = '0' + datevar number = now.getSeconds()%43 //这将产生一个基于目前时间的0到42的整数。var time = year + month + date + hour + minuvar enNum = []for(var i=0;i<4;i++){var ranNum = Math.ceil(Math.random() * 25) //生成一个0到25的数字//大写字母'A'的ASCII是65,A~Z的ASCII码就是65 + 0~25然后调用String.fromCharCode()传入ASCII值返回相应的字符并push进数组里enNum.push(String.fromCharCode(65 + ranNum))}return time+'_'+number+enNum.join('')+'.png'
}//base64转文件流
function dataURLtoFile(dataurl, filename) {// 将base64编码转为字符串const bstr = window.atob(dataurl)let n = bstr.lengthconst u8arr = new Uint8Array(n) // 创建初始化为0的,包含length个元素的无符号整型数组while (n--) {u8arr[n] = bstr.charCodeAt(n)}return new File([u8arr], filename, {type: 'image/png'})
}//关闭弹框
function modalClose(){$('#cameraModal').modal('hide')if(cameraIsOpen){mediaStreamTrack.stop() // 关闭摄像头}
}