背景
来了来了,用户奇怪的需求又来了,是这样的,原生的文件上传,在移动设备上是可以调用摄像头现拍然后直接上传的,而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.getUserMedia
if (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 =stream
video.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 =stream
video.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 + 1
if (month < 10) month = '0' + month
if (date < 10) date = '0' + date
var number = now.getSeconds()%43 //这将产生一个基于目前时间的0到42的整数。
var time = year + month + date + hour + minu
var 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.length
const 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() // 关闭摄像头
}
}