box-sizing-50

问题描述:vuepc电脑可以获取设备吗 大家好,给大家分享一下一个有趣的事情,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!

如何在VSCode解决办法可以设置div的box-sizing:border-box(盒模型)~

box-sizing-50的相关图片

VUE2实现录像(PC端)可拍照 下载 预览 选取指定摄像头和麦克风设备 源代码可直接使用 原创。

2022-10-16 17:57:44。

嗯呐FT 

码龄1年

关注

2022.10月份 谷歌是最新版本 使用vue2写 。

下面的这些代码可以在谷歌浏览器的本地(localhost)和https环境下执行。中间有大量的注释可查看,基本上看一遍就懂,前面的坑我基本都踩过了。

如果是http环境的话,我下面这些代码是执行不了的,因为我做了获取指定设备的功能,如果要http环境中使用,需要把获取指定设备的相关代码删掉才能用,而且需要去谷歌的这个地址配置一下才能用,最下面我会介绍怎么在http环境中用。

功能如下:

1.可获取多个摄像头设备并选择其一进行录制。

2.录制的过程中拔掉摄像头监听结束录制。

3.可在录制中进行拍照生成png图片 可预览 可下载。

4.录制完成会生成一个有声音和画面的webm格式视频 可在线预览下载。

5.录制的过程中计时(最小误差)

界面展示(界面我就做个小Demo 没有过多去弄好看点 重要是script部分)

先上代码 -- html部分

<template>。

<div class="publish">。

<div class="box">。

<div class="videoPart">。

<div class="videoRecord" @mouseenter="hoverVideo(0)" @mouseleave="hoverVideo(1)">。

<video id="videoCamera" :width="videoWidth" :height="videoHeight" autoPlay></video>。

<div class="hoverVideoOutside" v-if="ifHoverVideo && ifStartRecord" >。

<div class="hoverVideoInside">。

<div class="hoverVideoInsideInside">。

<div class="hoverVideoBtn"><div class="hoverVideoBtnInside"></div></div>。

<span>{{recordHMSTime}}</span>。

</div>。

</div>。

</div>。

</div>。

<canvas id="canvasCamera" class="canvas" :width="videoWidth" :height="videoHeight"></canvas> 。

<video v-if="showVideo" :src="videoSrc" autoplay controls></video>。

<img v-if="showImg" class="imgClass" :src="imgSrc" alt="">。

</div>。

<div>。

<el-select v-model="deviceId" placeholder="请选择摄像头" @change="selectVideoChange" @focus="findVideoDevice" :disabled="ifStartRecord">。

<el-option。

v-for="item in deviceArr"。

:key="item.deviceId"。

:label="item.label"。

:value="item.deviceId">。

</el-option>。

</el-select>。

<el-button v-if="!ifStartRecord" @click="startRecord" icon="el-icon-video-camera" size="small">开始录制</el-button>。

<el-button v-else @click="stopRecord" icon="el-icon-switch-button" size="small">结束录制</el-button>。

<el-button @click="photographBtn" icon="el-icon-camera" size="small">拍照</el-button>。

</div>。

<vxe-table。

border

resizable。

show-overflow。

ref="xTable"。

height="500"。

:row-config="{isHover: true}"。

:data="tableData">。

<vxe-column type="seq" width="60"></vxe-column>。

<vxe-column field="name" title="Name"></vxe-column>。

<vxe-column title="操作" width="200" show-overflow>。

<template #default="{ row }">。

<vxe-button type="text" icon="vxe-icon-edit" @click="preview(row)">预览</vxe-button>。

<vxe-button type="text" icon="vxe-icon-edit" @click="download(row)">下载</vxe-button>。

</template>。

</vxe-column>。

</vxe-table>。

</div> 。

</div>

</template>。

CSS代码

<style scoped>。

.canvas{

opacity: 0!important;。

}

.videoPart{

position: relative;。

display: flex;。

align-items: center;。

}

.hoverVideoOutside{。

position: absolute;。

top: 0px;

left: 0px;

width: 500px;。

height: 300px;。

background:linear-gradient(#000,transparent 20%);。

z-index: 999;。

}

.hoverVideoInside{。

position: relative;。

width: 100%;。

height: 100%;。

}

.hoverVideoInsideInside{。

position: absolute;。

top: 10px;

left: 380px;。

padding: 2px;。

display: flex;。

justify-content: center;。

align-items: center;。

}

.hoverVideoBtn{。

width: 30px;。

height: 30px;。

border-radius: 50%;。

border: 2px solid red;。

padding: 3px;。

box-sizing: border-box;。

margin-right: 4px;。

}

.hoverVideoBtnInside{。

background: red;。

width: 20px;。

height: 20px;。

border-radius: 50%;。

box-sizing: 50%;。

}

span{

color: #fff;。

}

.videoRecord{。

position: relative;。

}

.imgClass{

width: 500px;。

height: 300px;。

}

</style>

逻辑部分

<script>

export default {。

name: 'HelloWorld',。

data() {

return {

ifOpenCamera: false,//控制摄像头开关。

ifStartRecord:false, //是否开始录制。

thisVideo: null,。

thisContext: null, //canvas。

thisCanvas: null,。

videoWidth: 500,。

videoHeight: 300,。

videoCecorded: [], //接受的数据流。

mediaRecorderData: {},。

videoSrc:'', //录制完的视频预览。

imgSrc:'',//录制完预览的图片地址。

deviceArr:[],//获取该电脑的摄像头。

deviceId:'', //选择哪个摄像头。

tableData:[], //录制完 制作表格数据。

showVideo:false, //录制完预览视频。

showImg:false,//录制完预览图片。

recordTime:0, //监听录像的时间。

recordHMSTime:'00:00:00', //监听录像的时间。

ifHoverVideo:false, //监听是否鼠标在视频的上面 显示录制时间。

timer:null, //每一秒执行一次计算录像的时间 这个是有误差的。

startTime:'', //记录开始录制的时间戳。

stream:null,。

}

},

created() {

this.initDevice();。

},

methods: {

initDevice(){。

this.$nextTick(() => {。

this.videoCecorded = []。

this.mediaRecorderData = null。

this.thisCanvas = document.getElementById('canvasCamera');。

this.thisContext = this.thisCanvas.getContext('2d');。

this.thisVideo = document.getElementById('videoCamera');。

// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象。

console.log('navigator.mediaDevices', navigator.mediaDevices)。

if (navigator.mediaDevices === undefined) {。

navigator.mediaDevices = {}。

this.dialogVisible = !this.dialogVisible;。

console.log('http环境下没开那个谷歌权限 所以有点问题 得弹出提示弹窗 如果是本地或者https环境就基本不会走到这里')。

this.$message({。

message: '去谷歌浏览器配置网址',。

type: 'error'。

})

}

// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象。

// 使用getUserMedia,因为它会覆盖现有的属性。

// 这里,如果缺少getUserMedia属性,就添加它。

if (navigator.mediaDevices.getUserMedia === undefined) {。

navigator.mediaDevices.getUserMedia = function (constraints) {。

// 首先获取现存的getUserMedia(如果存在)。

let 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)。

})

}

}

this.findVideoDevice()。

})

},

// 每次点开下拉框的时候都要去获取现在有多少个设备 以防在打开这个网站之后把摄像头拔了等情况 。

async findVideoDevice(){。

this.deviceId = ''。

this.deviceArr = []。

const _this = this。

try{

// 获取你电脑中有什么设备。

let deviceArr = await navigator.mediaDevices.enumerateDevices();。

if(this.deviceArr.length == 0){。

this.$message({。

message: '没有摄像头设备',。

type: 'error'。

})

this.deviceArr = []。

return 。

}

console.log('设备',deviceArr)。

deviceArr.forEach(item=>{。

if(item.kind == 'videoinput'){。

this.deviceArr.push(item) //获取你电脑中有多少个摄像头设备。

}

})

}catch(error){。

console.log(error)。

this.deviceArr = []。

}

},

// 选择完是哪个摄像头以后执行的方法。

selectVideoChange(){。

this.$nextTick(() => {。

const _this = this;。

const constraints = {。

audio: true,。

video: { 。

width: _this.videoWidth, 。

height: _this.videoHeight, 。

transform: 'scaleX(-1)',。

deviceId:{exact:this.deviceId} 。

},

};

navigator.mediaDevices.getUserMedia(constraints).then(async(stream)=>{。

// 旧的浏览器可能没有srcObject。

if ('srcObject' in _this.thisVideo) {。

_this.thisVideo.srcObject = stream。

} else {。

// 避免在新的浏览器中使用它,因为它正在被弃用。

_this.thisVideo.src = window.URL && window.URL.createObjectURL(stream)。

} 。

_this.thisVideo.onloadedmetadata = function (e) {。

_this.thisVideo.play()。

} 。

_this.ifOpenCamera = true 。

}).catch(err => {。

this.errReponse(err)。

});

});

},

// 开始录制

startRecord() {。

if(this.deviceId == ''){。

this.$message({。

message: '请选择摄像头',。

type: 'error'。

})

return

}

const _this = this。

this.mediaRecorderData = null。

this.videoCecorded = []。

this.$nextTick(()=>{。

const constraints = {。

audio: true,。

video: { 。

width: this.videoWidth, 。

height: this.videoHeight, 。

transform: 'scaleX(-1)',。

deviceId:{exact:this.deviceId} //选取指定的设备来录制。

},

};

//必须在model中render后才可获取到dom节点,直接获取无法获取到model中的dom节点。

navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {。

_this.stream = stream。

// 这个要重写一次 。

// 我插第三方的视频录像设备的情况下 点击录像 然后把设备拔出来 这个时候画面是黑色的 。

// 如果没有重写下面的方法 插进设备后 点击录像 画面依然是黑色的 但是能录像 只是界面上不显示 。

if ('srcObject' in _this.thisVideo) {。

_this.thisVideo.srcObject = stream。

} else {。

// 避免在新的浏览器中使用它,因为它正在被弃用。

_this.thisVideo.src = window.URL && window.URL.createObjectURL(stream)。

}

_this.thisVideo.onloadedmetadata = function (e) {。

_this.ifOpenCamera = true 。

_this.thisVideo.play()。

}

_this.startRecording(stream);//调用录制控件方法,触发开始录制。

}).catch(err => {。

// 点录制之前断开设备连接 但选择框已经选了设备 就会触发这个err。

this.errReponse(err)。

});

})

},

//拍照按钮

photographBtn() {。

//先判断是否开启了摄像头。

if(!this.ifOpenCamera){。

this.$message({。

message: '摄像头都还没开呢 傻猪猪',。

type: 'error'。

})

return

}

// 点击,canvas画图。

this.thisContext.drawImage(this.thisVideo, 0, 0, this.videoWidth, this.videoHeight);。

// 如果图片尺寸不想 500 300 那就写下面这个。

// this.thisContext.drawImage(this.thisVideo, 0, 0, this.videoWidth, this.videoHeight,0,0,1000, 600); 。

const fileName = (new Date).toISOString().replace(/:|\./g,'-')。

const a = this.thisCanvas.toDataURL('image/png')。

const file = this.dataURLtoFile(a,fileName + 'png')。

this.tableData.push({。

id:2,

name:fileName + 'png',。

url:this.thisCanvas.toDataURL('image/png'),。

type:'png'。

})

},

//停止录制

stopRecord() {。

if (this.thisVideo && this.thisVideo !== null) {。

this.mediaRecorderData.stop(); //结束录制。

}

},

// 开始录制中

startRecording(stream) {。

console.log('stream 在开始的时候的',stream)。

let _this = this。

this.mediaRecorderData = new MediaRecorder(stream, {。

mimeType: 'video/webm;codecs=vp8,opus' //不加这个codecs=vp8,opus有时候下载下来之后看几秒就没了 残缺的视频。

});

this.mediaRecorderData.addEventListener("dataavailable", (e) => {。

if (e.data.size > 0) {。

_this.videoCecorded.push(e.data);//视频录制视频流数据 。

};

});

this.mediaRecorderData.addEventListener("stop", () => {。

console.log("结束录制");。

_this.updataVideo();//上传实时录制的视频。

_this.ifStartRecord = false。

_this.recordTime = 0。

_this.recordHMSTime = '00:00:00'。

clearTimeout(_this.timer)。

_this.timer = null。

});

this.mediaRecorderData.addEventListener("start", (e) => {。

console.log("开始 录制");。

_this.ifStartRecord = true。

_this.recordTime = 0。

_this.startTime = new Date().getTime();。

_this.timer = setTimeout(_this.fixed,1000)。

});

this.mediaRecorderData.start()。

},

// 上传录制视频方法,获取视频地址。

updataVideo() {。

const blob = new Blob(this.videoCecorded, {。

type: 'video/webm'。

});

const fileName = (new Date).toISOString().replace(/:|\./g,'-')。

this.tableData.push({。

id:2,

type:'webm',。

name:fileName + '.webm',。

url:URL.createObjectURL(blob)。

})

},

// 预览视频 图片

preview(row){。

if(row.type == 'png'){。

this.showImg = true。

this.showVideo = false。

this.imgSrc = row.url。

}else if(row.type == 'webm'){ 。

this.showVideo = true。

this.showImg = false。

this.videoSrc = row.url。

}else{

this.$message({。

message: '无法预览',。

type: 'error'。

})

}

},

download(row){。

let aTag = document.createElement('a');//创建一个a标签。

aTag.download = row.name;。

aTag.href = row.url;。

aTag.click();。

},

hoverVideo(num){。

if(num){

// 移出

this.ifHoverVideo = false。

}else{

// 移入

this.ifHoverVideo = true。

}

},

secondChangeMinute(second){。

const hour = parseInt(second / 3600)。

const min = parseInt(second / 60)。

const se = parseInt(second % 60)。

const cHour = hour<10?'0'+hour:hour。

const cMin = min<10?'0'+min:min。

const cSe = se<10?'0'+se:se。

return cHour + ':' + cMin + ':' + cSe。

},

fixed(){

this.recordTime += 1。

this.recordHMSTime = this.secondChangeMinute(this.recordTime)。

if(!this.stream.active){。

this.stopRecord()。

}

var offset = new Date().getTime() - (this.startTime + this.recordTime * 1000);。

var nextTime = 1000 - offset;。

if (nextTime < 0) nextTime = 0;。

this.timer = setTimeout(this.fixed, nextTime);。

},

errReponse(err){。

const message = err.message || err。

const response = {。

'permission denied': '浏览器禁止本页面使用摄像头或麦克风,请开启相关的权限',。

'requested device not found': '未检测到摄像头'。

}

console.log(response[ message.toLowerCase() ] || '未知错误');。

this.$message({。

message: response[ message.toLowerCase() ] || '未知错误',。

type: 'warning'。

})

},

dataURLtoFile: function(dataurl, filename) { 。

let arr = dataurl.split(','),。

mime = arr[0].match(/:(.*?);/)[1],。

bstr = atob(arr[1]),。

n = bstr.length,。

u8arr = new Uint8Array(n);。

while (n--) {。

u8arr[n] = bstr.charCodeAt(n);。

}

return new File([u8arr], filename, { type: mime });。

},

// 这个方法是给需要的人看的 演示打开摄像头的方法。

async openCamera(){。

await navigator.mediaDevices.getUserMedia({audio:true,video:true}).then(()=>{。

//我这个时候已经打开摄像头了。

}).catch(err=>{。

this.errReponse(err)。

})

},

// 这个方法是给需要的人看的 演示关闭摄像头的方法。

closeCamera(){。

this.thisVideo.srcObject.getTracks().forEach(item => {。

// 关闭当前所有已打开的设备(你刚刚选择的摄像头设备和你默认的麦克风)

item.stop()。

})

},

}

</script>。

问题解答区域:

1.录制的视频只能是webm格式吗?进度条呢?

答:我在写程序的时候发现只能写webm格式,如果是写MP4或者其他类型,视频下载下来是没有办法播放的,可能在移动端就没有问题,我还没有去尝试在移动端做这个功能。webm格式我所知道的有两个弊端,下载下来的时候无法拖动进度条,而且要在指定播放器中才能播放。如果想要解决这个进度条的问题,可以去看这个地址的解决方法。前端 mediaRecorder 录制视频源代码实例,和本地播放器无法定位进度条问题分析和解决_anne都的博客-CSDN博客_mediarecorder 进度条。

2.http问题

答:在http环境下是可以录制的,但是我上面的代码运行不了就是了。因为我添加了一个获取用户电脑中设备的功能,该功能在http环境下没有办法获取,可能是浏览器出于安全的问题。如果想要在http环境下录制,可以参考下面的这个地址,我也是百度了很久,看了很多别人的博客才得出的最终代码结果。地址如下:

=>1.JS调用媒体设备失败 --- getUserMedia undefine 问题(各浏览器配置方法)_<!--玄德-->的博客-CSDN博客_浏览器不支持getusermedia。

=>2.

PC端调用摄像头录制视频——vue标准写法_前端_森森的博客-CSDN博客_vue调用摄像头录像。

=>3.

JS基于页面实现音视频的录制(一)_画虎成鳖的博客-CSDN博客_js录制视频。

3.表格不一定要用vxetable,随便用 。

4.如果还有什么问题再在评论区问吧。。

的相关图片

盒子模型概述:

所有HTML元素都可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用。CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。盒模型允许我们在其它元素和周围元素边框之间的空间放置元素。下面的图片说明了盒子模型(Box Model):

盒子模型组成以及对应区域

盒子模型的组成:

Margin(外边距) - 清除边框外的区域,外边距是透明的。

Border(边框) - 围绕在内边距和内容外的边框。

Padding(内边距) - 清除内容周围的区域,内边距是透明的。

Content(内容) - 盒子的内容,显示文本和图像。

以上是html中盒子模型的结构,每个元素都可以用这个盒子模型来解析。在开发中,一个元素的样式表现形式,也是由这个盒子模型的每个部分来表现的。对应到css中样式的属性有一下几个纬度——

width, height, padding, border, margin。由于在不同的浏览器中,这几个属性所表示的盒子模型中的部分有所差异,所以又分为了标准盒子模型和怪异盒子模型。

一,标准盒子模型

解释:在标准盒子模型下

(1)css中的width, height属性,分别表示的是盒子模型中content的宽度和高度。

(2)css中的padding,表示的是盒子模型的的padding部分。

(3)css中的border,表示的是盒子模型中的border部分。

(4)css中的margin,表示的是盒子模型中的margin。

二,怪异盒子模型(ie盒子模型)

解释:在怪异盒子模型下

(1)css中的width, height属性,分别表示的是盒子模型中content的宽度和高度加上盒子模型中padding和border的宽度。

(2)css中的padding,表示的是盒子模型的的padding部分。

(3)css中的border,表示的是盒子模型中的border部分。

(4)css中的margin,表示的是盒子模型中的margin。

**段落性总结 —— 标准盒子模型和怪异盒子模型的区别**。

从上述的内容可以看出,标准盒子模型和怪异盒子模型的区别,完全体现在css中width和height这两个属性对盒子模型的表现上。

标准盒子模型:css中width/height=content的width/height。

怪异盒子模型:css中width/height=content的width/height+padding+border。

导致的结果:

由于标准盒子模型和怪异盒子模型的存在,这就导致当同一段css代码作用在同一个元素上时,在不同盒子模型下的浏览器中,元素所占的宽度和高度却不同。

三,css3中box-sizing下的盒子模型。

语法:(属性)box-sizing: (属性值)content-box/border-box/inherit;

box-sizing对盒子模型的影响:

(1)当“box-sizing“的值为”content-box“时,css中的width所包含的部分是盒子模型中content的宽度。此时和标准盒子模型表现一致。

(2)当“box-sizing“的值为”border-box“时,css中的width所包含的是盒子模型中的content的宽度+padding+border的宽度。此时和怪异盒子模型的表现一致。

总结:box-sizing属性,让开发人员可以控制浏览器的是以标准盒子模型表现,还是以怪异盒子模型表现。

box-sizing的兼容性:

到此盒子模型的所有内容全部阐述完毕。

最佳方案:由于box-sizing的兼容性在ie8及以上,那在不要求兼容ie8一下的项目中,可以使用box-sizing给所有元素统一设置盒子模型的表现形式。个人推荐:。

*{box-sizing:'border-box'}。

这样只要设置的width的宽度,就是这个元素在页面中真实的宽度了。不用再去计算padding和border对width的影响。

对于需要兼容ie8的项目,就需要针对不同的浏览器,添加特定的代码。或者避免指定宽度的元素border和padding的设置。

相关内容:

1.行内元素之间的水平margin,即两个元素margin之和。

2.块级元素之间的竖直margin, 即取最大的。

3.嵌套盒子之间的margin,即父元素的padding+子元素的margin。

4.margin可以设置为负值。

不同浏览器的css前缀:Element {。

-moz-box-sizing: content-box;。

-webkit-box-sizing: content-box;。

-o-box-sizing: content-box;。

-ms-box-sizing: content-box;。

box-sizing: content-box;。

参考:

w3c标准:https://www.runoob.com/cssref/css3-pr-box-sizing.html。

的相关图片

的相关图片

原文地址:http://www.qianchusai.com/box-sizing-50.html

xiaoxue/16589

xiaoxue/16589

lw/汽车生日蛋糕图片男孩,汽车生日蛋糕图片2021最新款

lw/汽车生日蛋糕图片男孩,汽车生日蛋糕图片2021最新款

小兵别-30,小兵别打我破解版无限钻石无限金币

小兵别-30,小兵别打我破解版无限钻石无限金币

xiaoxue/20820

xiaoxue/20820

xiaoxue/21135

xiaoxue/21135

snot-110

snot-110

天天刷大G什么梗

天天刷大G什么梗

成年版one一个致敬韩寒下载

成年版one一个致敬韩寒下载

104在爱情里意思是什么,104在爱情代表什么意思

104在爱情里意思是什么,104在爱情代表什么意思

cc/赣州火车站图片大全,赣州火车站具体位置

cc/赣州火车站图片大全,赣州火车站具体位置